もやもやエンジニア

IT系のネタで思ったことや技術系のネタを備忘録的に綴っていきます。フロント率高め。

GolangとTravisでCIしてみる

GolangTravisを連携したときのメモ。

Golangでテスト書くよ

testingというTest用のパッケージがあらかじめ用意されているので、それを使ってみます。使い方はこんな感じ。

テスト対象のコード
sample.go

package main

func main(){
}

func sum(v1 int, v2 int) int {
    return v1+v2
}

テストコード
sample_test.go

package main

import "testing"

func Test_sum(t *testing.T) {
    if sum(1,2) != 3 {
        t.Error("fail sum")
    }
}
  • Test***で始まるメソッドがテストの実行対象になります。詳しくは testing - The Go Programming Language
  • testingにはassertのようなものは無く、ごり押しでif文書く感じ。他にもTest用のパッケージはあるみたいですが、とりあえず本家で用意されているものを使います。

Testを動かしてみる

  • テストは以下のコマンドで実行され、実行するとつらつらとテスト結果が表示されます。-vオプションはテストの詳細を表示するオプションです。
$ go test -v

=== RUN Test_sum
--- PASS: Test_sum (0.00 seconds)
PASS
ok  	_/Users/rei_m/Documents/go/travisSample	0.010s

Travisと連携する

  • .travis.ymlを作成してGithubに置いた後、Travis側でチェックをオンにします。
language: go

script:
 - go test -v

では、意図的にTestを失敗させてみます。上のsumのTestメソッドが合わないように修正してローカルでテストを動かしてみます。

func Test_sum(t *testing.T) {
    if sum(1,2) != 4 {
        t.Error("fail sum")
    }
}
$ go test -v

=== RUN Test_sum
--- FAIL: Test_sum (0.00 seconds)
	sample_test.go:7: fail sum
FAIL
exit status 1
FAIL	_/Users/rei_m/Documents/go/travisSample	0.008s

テストがこけてtestingのErrorメソッドにセットした文字列が表示されています。この状態でGithubにpushしてみます。

f:id:Rei19:20141013204701p:plain
「add fail case」が今回のcommitです。Travis上でテストがこけてmergeすんなよと教えてくれているのがわかります。

では、先ほどのコードをテストが動く状態に戻してpushしてみます。

f:id:Rei19:20141013205124p:plain

今度はテストが通ってmergeしても大丈夫ということがわかりました。pushを契機にTravis上でテストが正しく実行されています。

httpServerのテスト

golangはhttpパッケージが用意されていて、簡単にhttpサーバーが立てられます。その場合のテストも試してみました。先ほどのコードにhttpサーバーを立てるコードを追加します。

sample.go

package main

import (
  "fmt"
  "net/http"
)

func main(){
  handler := createHandler("{\"sample\":\"sampleValue\"}")
  http.HandleFunc("/", handler)
  http.ListenAndServe(":8080", nil)
}

func sum(v1 int, v2 int) int {
    return v1+v2
}

func createHandler(res string) (func(w http.ResponseWriter, r *http.Request)) {
  return func(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Access-Control-Allow-Origin", "*")
    w.Header().Set("Content-Type", "application/json")
    fmt.Fprintf(w, res)
    return
  }
}

createHandlerでhandlerを作成してmainメソッドでlistenしています。処理は渡したJSONをそのまま表示するだけのシンプルなものです。では起動してみます。

$ go run sample.go

portは8080でlistenしているのでブラウザでlocalhost:8080を表示します。

f:id:Rei19:20141013210459p:plain

設定したJSONが表示されていますね。では、このhandler用のテストコードを追加します。

sample.go

package main

import (
  "io/ioutil"
  "net/http"
  "net/http/httptest"
  "testing"
)

func Test_sum(t *testing.T) {
  if sum(1, 2) != 3 {
    t.Error("fail sum")
  }
}

func Test_createHandler(t *testing.T) {

  response := "{\"test\":\"testValue\"}"
  handler := createHandler(response)
  server := httptest.NewServer(http.HandlerFunc(handler))
  defer server.Close()
  if res, err := http.Get(server.URL); err != nil {
    t.Error(err)
  } else {
    if res.StatusCode != 200 {
      t.Error("fail Test_createHandler 1")
    } else {
      if body, err := ioutil.ReadAll(res.Body); err != nil {
        t.Error(err)
      } else {
        if response != string(body) {
          t.Error("fail Test_createHandler 2")
        }
      }
    }
    res.Body.Close()
  }
  return
}

Test_createHandlerというテスト用のメソッドを追加しました。この中で注目するのはhttptestというパッケージです。httptest.NewServerメソッドにテスト対象のhandlerを渡す事でテスト用のserverを返してくれるので、そこからResponseを取得してチェックできます。sampleでは渡したJSON文字列とResponseを比較して合っているかどうか見ています。

$ go test -v

=== RUN Test_sum
--- PASS: Test_sum (0.00 seconds)
=== RUN Test_createHandler
--- PASS: Test_createHandler (0.00 seconds)
PASS
ok  	_/Users/rei_m/Documents/go/travisSample	0.016s

作成したTest_createHandlerもテストが通りました。もちろんpushしてTravis上でテストしても同じ結果が返ります。

今回作ったコードはこちら
rei-m/go-Travis · GitHub