214
159

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Go 言語 testing チートシート

Last updated at Posted at 2018-03-22

はじめに

このページでは testing パッケージの詳しい Example をチートシートとしてまとめました。

ご案内

このページの内容を別サイトにまとめなおしました。

目的別に項目を分けたのでやりたいことからコードを逆引きできます。

また、サイト上でコードを即時実行できるように The Go Playground の実行フォームを埋め込んだので、気軽にコードをお試しいただけます。

目次

テストファイルを作成する

  • テスト用のファイルはテスト対象と同じディレクトリで 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.Logt.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 ディレクトリに入れる
  • testdatago 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.Readerio.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.Readerio.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 ./...

おわりに

214
159
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
214
159

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?