はじめに
このページでは testing パッケージの詳しい Example をチートシートとしてまとめました。
ご案内
このページの内容を別サイトにまとめなおしました。
目的別に項目を分けたのでやりたいことからコードを逆引きできます。
また、サイト上でコードを即時実行できるように The Go Playground の実行フォームを埋め込んだので、気軽にコードをお試しいただけます。
目次
- 関数のテストを書く
- テストを実行する
- メソッドのテストをする
- テスト失敗時にテストを継続する・テストを即時終了する
- 複数のテストデータでテストする
- テストを階層化する
- テストの開始終了処理を行う
- パッケージ単位でテストの開始終了処理を行う
- 別ファイルのテストデータを読み込む
- 入出力を持つ関数のテストをする
- HTTP ハンドラーをテストする
- HTTP サーバーをテストする
テストファイルを作成する
- テスト用のファイルはテスト対象と同じディレクトリで
xxx_test.go
という名前で作成する。 - テスト対象が
foo.go
ならfoo_test.go
とする。
関数のテストを書く
- こちらの加算をするだけの
adder.go
ファイルのAdd
関数のテストをしたいとすると
basic/adder.go
package basic
func Add(l, r int) int {
return l + r
}
- テスト用のファイルの名前は
adder_test.go
となり関数名はTestAdd
となる
basic/adder_test.go
package basic
import "testing"
// テスト用の関数の定義.
// テスト用の関数名は TestXxx という形式で Add 関数のテストなら TestAdd とする.
func TestAdd(t *testing.T) {
var result int
// テストケースの検証.
// テストしたい関数の実行結果を if などで判定して想定した値であるかを検証する.
result = Add(1, 2)
if result != 3 {
// テスト失敗時には t.Error などでエラーを表示する.
t.Errorf("add failed. expect:%d, actual:%d", 3, result)
}
// テスト中のロギング.
// t.Log, t.Logf でログを出すと `go test -v` と実行したときのみ表示される.
t.Logf("result is %d", result)
}
テストを実行する
- テストは
go test
コマンドで実行する
$ go test -v
=== RUN TestAdd
--- PASS: TestAdd (0.00s)
adder_test.go:20: result is 3
エラー関数の比較
- testing パッケージのエラー関連の関数の挙動を比較する
basic/adder_test.go
// t.Error はテスト失敗としてログを出すが以後の処理も実行される.
// t.Errorf は出力のフォーマット指定ができるだけで挙動は同じ.
func TestAdd2(t *testing.T) {
t.Error("error")
t.Log("log")
}
// t.Fatal はテスト失敗としてログを出し以後の処理は実行されない.
// t.Fatalf は出力のフォーマット指定ができるだけで挙動は同じ.
func TestAdd3(t *testing.T) {
t.Fatal("fatal")
t.Log("log")
}
// t.Fail はテスト失敗とするが以後の処理も実行される.
func TestAdd4(t *testing.T) {
t.Fail()
t.Log("log")
}
// t.FailNow はテスト失敗とし以後の処理は実行されない.
func TestAdd5(t *testing.T) {
t.FailNow()
t.Log("log")
}
実行結果
=== RUN TestAdd2
--- FAIL: TestAdd2 (0.00s)
adder_test.go:24: error
adder_test.go:25: log
=== RUN TestAdd3
--- FAIL: TestAdd3 (0.00s)
adder_test.go:29: fatal
=== RUN TestAdd4
--- FAIL: TestAdd4 (0.00s)
adder_test.go:35: log
=== RUN TestAdd5
--- FAIL: TestAdd5 (0.00s)
レシーバ付きの関数のテストをする
- struct などから呼び出されるレシーバ付きの関数のテストの場合はテスト用の関数名にレシーバ名が入る
basic/adder.go
type Adder struct{}
func (a *Adder) Add(l, r int) int {
return l + r
}
func (a *Adder) AddMulti(n ...int) int {
var sum int
for _, m := range n {
sum += m
}
return sum
}
basic/adder_test.go
// レシーバを持つ関数のテスト用の関数名は TestReceiver_Func という形式.
// Adder 型のレシーバを持つ Add 関数のテストなので TestAdder_Add
func TestAdder_Add(t *testing.T) {
a := &Adder{}
// 一つの処理に対して複数のテストケースをまとめてテストしたい場合はテストケース用の型の配列を定義して実行するパターンがよく使われておりテーブル駆動テストと呼ばれる.
testCases := []struct {
L int
R int
Result int
}{
{1, 2, 3},
{0, 0, 0},
{0, -1, -1},
{100, 200, 0}, // 失敗するケース. 失敗時の出力を確認する.
}
for _, testCase := range testCases {
result := a.Add(testCase.L, testCase.R)
if result != testCase.Result {
t.Errorf("invalid result. testCase:%#v, actual:%d", testCase, result)
}
}
}
実行結果
# go test -run REGEX で REGEX にマッチするテストだけ実行できる
$ go test -v -run Adder
=== RUN TestAdder_Add
--- FAIL: TestAdder_Add (0.00s)
adder_test.go:92: invalid result. testCase:struct { L int; R int; Result int }{L:100, R:200, Result:0}, actual:200
テストの開始終了処理を実行する
- サブテストを使うと任意の粒度でテストの開始終了処理を定義することができる
basic/adder_test.go
// サブテストの実行.
// サブテストを使うことで容易にテスト前後の処理を定義できる.
// テスト関数内で t.Run を使うことでサブテストが実行できる.
func TestAdder_AddMulti(t *testing.T) {
// テスト開始処理
t.Log("setup")
// サブテスト. t.Run() が順次実行される.
t.Run("Len=1", func(t *testing.T) {
t.Log("Len=1")
if new(Adder).AddMulti(1) != 1 {
t.Fail()
}
})
t.Run("Len=2", func(t *testing.T) {
t.Log("Len=2")
if new(Adder).AddMulti(1, 2) != 3 {
t.Fail()
}
})
t.Run("Len=3", func(t *testing.T) {
t.Log("Len=3")
if new(Adder).AddMulti(1, 2, 3) != 6 {
t.Fail()
}
})
// テスト終了処理
t.Log("tear-down")
}
実行結果
$ go test -v -run AddMulti
=== RUN TestAdder_AddMulti
=== RUN TestAdder_AddMulti/Len=1
=== RUN TestAdder_AddMulti/Len=2
=== RUN TestAdder_AddMulti/Len=3
--- PASS: TestAdder_AddMulti (0.00s)
adder_test.go:112: setup
--- PASS: TestAdder_AddMulti/Len=1 (0.00s)
adder_test.go:115: Len=1
--- PASS: TestAdder_AddMulti/Len=2 (0.00s)
adder_test.go:122: Len=2
--- PASS: TestAdder_AddMulti/Len=3 (0.00s)
adder_test.go:129: Len=3
adder_test.go:135: tear-down
# -run で "/" 以後にサブテスト名を指定すると任意のサブテストだけ実行できる
$ go test -v -run AddMulti/Len=3
=== RUN TestAdder_AddMulti
=== RUN TestAdder_AddMulti/Len=3
--- PASS: TestAdder_AddMulti (0.00s)
adder_test.go:112: setup
--- PASS: TestAdder_AddMulti/Len=3 (0.00s)
adder_test.go:129: Len=3
adder_test.go:135: tear-down
サブテストを並列実行する
- サブテスト内で
t.Parallel()
を実行することでサブテストが並列実行される
basic/adder_test.go
func TestAdder_AddMulti2(t *testing.T) {
// テストの開始終了と各サブテストの終了で時間を表示して実行順を確認する
t.Logf("setup: %s", time.Now())
// 並列実行されるサブテストを t.Run でラップすることで全てのサブテストの終了を待つ.
// こうすることで全てのサブテストの終了を待ってテスト終了処理を実行することができる.
t.Run("group", func(t *testing.T) {
t.Run("Len=1", func(t *testing.T) {
// サブテストを並列実行する
t.Parallel()
// 並列実行されていることを確認するため sleep で終了タイミングをずらす
time.Sleep(time.Second * 2)
if new(Adder).AddMulti(1) != 1 {
t.Fail()
}
t.Logf("Len=1: %s", time.Now())
})
t.Run("Len=2", func(t *testing.T) {
t.Parallel()
time.Sleep(time.Second * 3)
if new(Adder).AddMulti(1, 2) != 3 {
t.Fail()
}
t.Logf("Len=2: %s", time.Now())
})
t.Run("Len=3", func(t *testing.T) {
t.Parallel()
time.Sleep(time.Second * 1)
if new(Adder).AddMulti(1, 2, 3) != 6 {
t.Fail()
}
t.Logf("Len=3: %s", time.Now())
})
})
t.Logf("tear-down: %s", time.Now())
}
実行結果
$ go test -v -run AddMulti2
=== RUN TestAdder_AddMulti2
=== RUN TestAdder_AddMulti2/group
=== RUN TestAdder_AddMulti2/group/Len=1
=== RUN TestAdder_AddMulti2/group/Len=2
=== RUN TestAdder_AddMulti2/group/Len=3
--- PASS: TestAdder_AddMulti2 (3.00s)
adder_test.go:174: setup: 2018-03-21 09:56:04.979988051 +0900 JST
--- PASS: TestAdder_AddMulti2/group (0.00s)
--- PASS: TestAdder_AddMulti2/group/Len=3 (1.01s)
adder_test.go:205: Len=3: 2018-03-21 09:56:05.9852616 +0900 JST
--- PASS: TestAdder_AddMulti2/group/Len=1 (2.00s)
adder_test.go:187: Len=1: 2018-03-21 09:56:06.981221633 +0900 JST
--- PASS: TestAdder_AddMulti2/group/Len=2 (3.00s)
adder_test.go:196: Len=2: 2018-03-21 09:56:07.983102269 +0900 JST
adder_test.go:209: tear-down: 2018-03-21 09:56:07.983340171 +0900 JST
テストヘルパースクリプトを利用する
-
t.Helper()
を実行するとヘルパースクリプト内で実行したt.Log
やt.Error
の出力元がヘルパースクリプト内ではなく呼び出し元のものになる. - ヘルパースクリプトが同一テスト内で複数回呼ばれていると
t.Error
などがどの回のヘルパースクリプトから出力されているものかわかりづらいので判断するのに便利.
basic/adder_go
func TestAdder_AddMulti3(t *testing.T) {
t.Run("group", func(t *testing.T) {
helperFunc(t, false)
helperFunc(t, true) // helperFunc 内で t.Helper を実行するので Log や Error が発生した際にこの行から出ていることになりデバッグが楽になる.
})
}
func helperFunc(t *testing.T, useHelper bool) {
if useHelper {
t.Helper()
}
t.Logf("use helper: %v", useHelper)
}
実行結果
$ go test -v -run AddMulti3
=== RUN TestAdder_AddMulti3
=== RUN TestAdder_AddMulti3/group
--- PASS: TestAdder_AddMulti3 (0.00s)
--- PASS: TestAdder_AddMulti3/group (0.00s)
adder_test.go:245: use helper: false
adder_test.go:238: use helper: true
パッケージ単位でテスト開始終了処理を実装する
-
func TestMain(m *testing.M)
というテスト関数を定義するとテストコマンド実行時に同一パッケージ内のテスト関数がこの関数を経由して実行される - これを利用してパッケージ内のテストの開始処理と終了処理を容易に定義することができる
- 具体的な挙動は以下のように
testmain
パッケージにa_test.go
,b_test.go
,main_test.go
が置いてある場合のテスト実行結果から確認できる
testmain/a_test.go
func TestA(t *testing.T) {
t.Log("TestA")
}
testmain/b_test.go
func TestB(t *testing.T) {
t.Log("TestB")
}
testmain/main_test.go
package testmain
import (
"testing"
"os"
"log"
)
func TestMain(m *testing.M) {
// 開始処理
log.Print("setup")
// パッケージ内のテストの実行
code := m.Run()
// 終了処理
log.Print("tear-down")
// テストの終了コードで exit
os.Exit(code)
}
実行結果
$ go test -v
2018/03/21 16:41:48 setup
=== RUN TestA
--- PASS: TestA (0.00s)
a_test.go:6: TestA
=== RUN TestB
--- PASS: TestB (0.00s)
b_test.go:6: TestB
PASS
2018/03/21 16:41:48 tear-down
テストデータのフィクスチャーを読み込む
- テスト用のデータは
testdata
ディレクトリに入れる -
testdata
はgo test
などの各種ツールから無視されるので安全に取り扱うことができる
fixture/a_test.go
package fixture
import (
"testing"
"io/ioutil"
"log"
"encoding/json"
"os"
)
// フィクスチャーを読み込むための型の定義
type Fixture struct {
TestCases []testCase `json:"test_cases"`
}
type testCase struct {
L int `json:"l"`
R int `json:"r"`
Result int `json:"result"`
}
// TestMain を使ってテスト実行前にフィクスチャーを読み込んでテスト環境を用意する
func TestMain(m *testing.M) {
// フィクスチャーを読み込む
b, err := ioutil.ReadFile("testdata/fixture.json")
if err != nil {
log.Fatal(err)
}
f := new(Fixture)
if err := json.Unmarshal(b, f); err != nil {
log.Fatal(err)
}
// ここではログ表示しているだけだが利用しているデータストアへデータの登録をするなどできる
log.Printf("fixture: %#v", f)
// テストの実行
os.Exit(m.Run())
}
func TestA(t *testing.T) {
t.Log("fixture/a_test.go")
}
fixture/testdata/fixture.json
{
"test_cases": [
{"l": 1, "r": 1, "result": 2},
{"l": 0, "r": 0, "result": 0},
{"l": 0, "r": -1, "result": -1},
{"l": 1, "r": -3, "result": -2}
]
}
実行結果
$ go test -v ./...
2018/03/21 21:22:16 fixture: &fixture.Fixture{TestCases:[]fixture.testCase{fixture.testCase{L:1, R:1, Result:2}, fixture.testCase{L:0, R:0, Result:0}, fixture.testCase{L:0, R:-1, Result:-1}, fixture.testCase{L:1, R:-3, Result:-2}}}
=== RUN TestA
--- PASS: TestA (0.00s)
a_test.go:41: fixture/a_test.go
入出力を持つ関数のテストをする
- go では入出力は
io.Reader
とio.Writer
として抽象化されることが多いので、両方のインターフェイスの実装として振る舞うことができるbytes.Buffer
を利用すると便利
io/io_test.go
package io
import (
"bytes"
"io"
"testing"
"testing/iotest"
)
// io.Reader と io.Writer による入出力のある関数のテストをする.
func TestReaderWriter(t *testing.T) {
// テスト用の io.Reader 実装を作成する.
// io.Reader のモックは bytes.Buffer を使ってテストするのが手軽.
text := "string from input buffer"
input := bytes.NewBufferString(text)
// テスト用の io.Writer 実装を作成する.
// io.Writer のモックも bytes.Buffer を利用できる.
output := new(bytes.Buffer)
// io.Copy(io.Writer, io.Reader) を実行してテキストをコピーする.
if _, err := io.Copy(output, input); err != nil {
t.Error(err)
}
// テキストがコピーできていることを確認する.
if output.String() != text {
t.Errorf("failed to copy. output:%v", output)
}
}
- また、
io.Reader
とio.Writer
の読み書きしている内容をログに出す便利ラッパーも併用するとよりテストしやすくなるかもしれない
io/io_test.go
// io.Reader に iotest.NewReadLogger をラップさせると Read されると同時に内容を標準エラー出力に表示する.
// io.Writer に対する iotest.NewWriteLogger も同じように動作する.
func TestReaderWriterWithDebugPrint(t *testing.T) {
input := bytes.NewBufferString("hello world")
output := new(bytes.Buffer)
_, err := io.Copy(
iotest.NewWriteLogger("output: ", output),
iotest.NewReadLogger("input: ", input))
if err != nil {
t.Error(err)
}
if output.String() != "hello world" {
t.Errorf("faild to copy. output:%v", output)
}
}
実行結果
=== RUN TestReaderWriterWithDebugPrint
2018/03/22 12:59:08 input: 68656c6c6f20776f726c64
2018/03/22 12:59:08 output: 68656c6c6f20776f726c64
2018/03/22 12:59:08 input: : EOF
--- PASS: TestReaderWriterWithDebugPrint (0.00s)
*/
net/http のハンドラーをテストする
- net/http のハンドラーの単体テストには httptest を使う
http/handler.go
package http
import (
"encoding/json"
"fmt"
"net/http"
)
func HelloHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "hello %s", r.FormValue("name"))
}
type JsonRequest struct {
Name string
}
type JsonResponse struct {
Message string
}
func JsonHandler(w http.ResponseWriter, r *http.Request) {
body := JsonRequest{}
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
}
b, err := json.Marshal(JsonResponse{Message: "hello " + body.Name})
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
}
w.Header().Set("Content-Type", "application/json")
fmt.Fprint(w, string(b))
}
http/handler_test.go
package http
import (
"bytes"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
)
// HelloHandler 単体でテストする
func TestHelloHandler(t *testing.T) {
// テスト用のリクエスト作成
req := httptest.NewRequest("GET", "http://example.com/?name=world", nil)
// テスト用のレスポンス作成
res := httptest.NewRecorder()
// ハンドラーの実行
HelloHandler(res, req)
// レスポンスのステータスコードのテスト
if res.Code != http.StatusOK {
t.Errorf("invalid code: %d", res.Code)
}
// レスポンスのボディのテスト
if res.Body.String() != "hello world" {
t.Errorf("invalid response: %#v", res)
}
t.Logf("%#v", res)
}
// JsonHandler 単体でテストする.
// POST のボディで JSON を受け取ってレスポンスで JSON を返すハンドラー.
func TestJsonHandler(t *testing.T) {
// テスト用の JSON ボディ作成
b, err := json.Marshal(JsonRequest{Name: "world"})
if err != nil {
t.Fatal(err)
}
// テスト用のリクエスト作成
req := httptest.NewRequest("POST", "http://example.com/", bytes.NewBuffer(b))
// テスト用のレスポンス作成
res := httptest.NewRecorder()
// ハンドラーの実行
JsonHandler(res, req)
// レスポンスのステータスコードのテスト
if res.Code != http.StatusOK {
t.Errorf("invalid code: %d", res.Code)
}
// レスポンスの JSON ボディのテスト
resp := JsonResponse{}
if err := json.NewDecoder(res.Body).Decode(&resp); err != nil {
t.Errorf("errpr: %#v, res: %#v", err, res)
}
if resp.Message != "hello world" {
t.Errorf("invalid response: %#v", resp)
}
t.Logf("%#v", resp)
}
net/http サーバーのテストをする
- ルーティングやミドルウェアなどの挙動も含めた結合テストをしたい場合は httptest.Server を利用する
http/server.go
package http
import "net/http"
type MyServer struct{}
func (s *MyServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
m := http.NewServeMux()
m.HandleFunc("/hello", HelloHandler)
m.HandleFunc("/json", JsonHandler)
m.ServeHTTP(w, r)
}
http/server_test.go
package http
import (
"bytes"
"encoding/json"
"io/ioutil"
"net/http"
"net/http/httptest"
"testing"
)
// http.Handler からテスト用のサーバーを起動してサーバー単位でのテストを行う.
// ハンドラー単体のテストと比べてルーティング設定やミドルウェアの挙動などもテストできる.
func TestMyServer_ServeHttp(t *testing.T) {
// テスト用のサーバーを起動
ts := httptest.NewServer(&MyServer{})
defer ts.Close()
// HelloHandler のテスト
res, err := http.Get(ts.URL + "/hello?name=world")
if err != nil {
t.Error(err)
}
if res.StatusCode != http.StatusOK {
t.Errorf("invalid response: %v", res)
}
body, err := ioutil.ReadAll(res.Body)
if err != nil {
t.Error(err)
}
res.Body.Close()
if string(body) != "hello world" {
t.Errorf("invalid body: %s", body)
}
// JsonHandler のテスト
b, err := json.Marshal(JsonRequest{Name: "world"})
if err != nil {
t.Fatal(err)
}
res, err = http.Post(ts.URL+"/json", "application/json", bytes.NewBuffer(b))
if err != nil {
t.Error(err)
}
if res.StatusCode != http.StatusOK {
t.Errorf("invalid response: %v", res)
}
resp := JsonResponse{}
if err := json.NewDecoder(res.Body).Decode(&resp); err != nil {
t.Error(err)
}
res.Body.Close()
if resp.Message != "hello world" {
t.Errorf("invalid message: %#v", resp)
}
}
Google App Engine のテストをする
- GAE の http ハンドラーのテストは goapp コマンドと aetest パッケージを使って模擬環境を立ち上げて実行する
- ここではまず Datastore を利用するハンドラーを定義する
gaehttp/handler.go
package gaehttp
import (
"fmt"
"net/http"
"google.golang.org/appengine"
"google.golang.org/appengine/datastore"
)
type User struct {
Name string
}
// パラメータで受け取った id のユーザーを Datastore から検索して "hello user.name" と返却するハンドラー.
func HelloHandler(w http.ResponseWriter, r *http.Request) {
ctx := appengine.NewContext(r)
id := r.FormValue("id")
key := datastore.NewKey(ctx, "User", id, 0, nil)
u := new(User)
if err := datastore.Get(ctx, key, u); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
fmt.Fprintf(w, "hello %s", u.Name)
}
- テストでは Datastore へデータが登録されている場合とされていない場合を検証する
gaehttp/handler_test.go
package gaehttp
import (
"net/http"
"net/http/httptest"
"testing"
"google.golang.org/appengine/aetest"
"google.golang.org/appengine"
"google.golang.org/appengine/datastore"
)
// HelloHandler 単体でテストする.
// ユーザーが存在しないので失敗するケース.
func TestHelloHandler_Failure(t *testing.T) {
// App Engine テスト用の環境を立ち上げる
instance, err := aetest.NewInstance(&aetest.Options{StronglyConsistentDatastore: true})
if err != nil {
t.Fatal(err)
}
defer instance.Close()
// App Engine テスト用のリクエストを作成
req, err := instance.NewRequest("GET", "http://example.com/?id=user1", nil)
if err != nil {
t.Fatal(err)
}
// テスト用のレスポンス作成
res := httptest.NewRecorder()
// ハンドラーの実行
HelloHandler(res, req)
// ユーザーが存在しないのでエラーになる
if res.Code != http.StatusInternalServerError {
t.Errorf("invalid code: %d", res.Code)
}
}
// HelloHandler 単体でテストする.
// 事前にユーザーを作成して成功するケース.
func TestHelloHandler_Success(t *testing.T) {
// App Engine テスト用の環境を立ち上げる
instance, err := aetest.NewInstance(&aetest.Options{StronglyConsistentDatastore: true})
if err != nil {
t.Fatal(err)
}
defer instance.Close()
// App Engine テスト用のリクエストを作成
req, err := instance.NewRequest("GET", "http://example.com/?id=user1", nil)
if err != nil {
t.Fatal(err)
}
// テスト用のレスポンス作成
res := httptest.NewRecorder()
// 事前にユーザーを作成する
ctx := appengine.NewContext(req)
key := datastore.NewKey(ctx, "User", "user1", 0,nil)
if _, err = datastore.Put(ctx, key, &User{Name: "world"}); err != nil {
t.Error(err)
}
// ハンドラーの実行
HelloHandler(res, req)
// ユーザーが存在しないのでリクエストに成功する
if res.Code != http.StatusOK {
t.Errorf("invalid code: %d", res.Code)
}
// レスポンスのボディのテスト
if res.Body.String() != "hello world" {
t.Errorf("invalid response: %#v", res)
}
t.Logf("%#v", res)
}
- テストコマンドは Google Cloud SDK に同梱されている
goapp test
コマンドを利用する
$ /path/to/goapp test
Travis CI を使う
手順
- .travis.yml をプロジェクトのルートに追加する
- コードを GitHub の public レポジトリに置く
- Travis CI のサイトに GitHub アカウントでサインインする
- 対象のプロジェクトを Travis CI 上で有効にする
- git push でテストを実行する
.trafis.yml
- dep で依存パッケージを管理している場合
.travis.yml
language: go
go:
- "1.9"
before_install:
- go get github.com/golang/dep/...
install:
- $GOPATH/bin/dep ensure
script:
- go test -v ./...
CircleCI を使う
手順
- .circleci/config.yml を追加する
- Sign in with github
- Add project でプロジェクトを追加
- ビルドを実行する
.circleci/config.yml
- dep で依存パッケージを管理している場合
.circleci/config.yml
version: 2
jobs:
build:
environment:
- GOPATH: /home/circleci/go
docker:
- image: circleci/golang:1.9
working_directory: /home/circleci/go/src/github.com/nirasan/go-testing-cheat-sheet
steps:
- checkout
- run: go get github.com/golang/dep/...
- run: ${GOPATH}/bin/dep ensure
- run: go test -v ./...
おわりに
- 動作するコードはリポジトリを参照のこと