goのテストの書き方【備忘録】


テスト実行

go test ./... -v

テストの流れ

各レイヤーのテストは基本的に下記の流れです。

  • mockを作成して
  • テスト対象のレシーバにセットして
  • テスト対象のメソッドを呼び出して
  • 結果を検証する

    t.Run("error", func(t *testing.T) {
        ctrl := gomock.NewController(t)
        GroupUsecase := mocks.NewMockIGroup(ctrl) -> mockを作る
        GroupUsecase.EXPECT().GetTopList().Return(nil, fmt.Errorf("test")) -> mockの挙動を決定
        h := &Group{
            GroupUsecase: GroupUsecase, -> セットして
        }
        e := echo.New()
        req := httptest.NewRequest(http.MethodPost, "/", nil)
        rec := httptest.NewRecorder()
        c := e.NewContext(req, rec)
        err := h.TopList(c) -> テスト対象メソッド呼出

        assert.Error(t, err) -> 結果を検証する
    })

gomock, mockgen

handler, usecaseは依存するinterfaceのmockをテスト中で実装していますが、mockはgomockを使って実装しています。

また、mockgenという定義したinterfaceからmockを作ってくれるツールも同梱しているのでmockはそれを使って生成しています。

$ go get github.com/golang/mock/gomock
$ go install github.com/golang/mock/mockgen

interfaceを追加、修正などしたらmockgen.shを実行してください。

sh mockgen.sh

すると、各レイヤーのmocks以下にmockが生成されます。

handler/mocks/
└── group.go

sqlmock

repositoryレイヤーはgorm.DBに依存しているのでgo-sqlmockを使ってgormが依存するdatabase/sqldatabase/mysqlをモックしてしまいます。

mockとは

各レイヤーはinterfaceを通じて依存しているので、interfaceを遵守するmockを代わりにセットすることで擬似的に各インスタンス呼び出しています。

mockを使うとモックDBなど用意する必要が無く原則ソースコード単体でテストを作ることができるようになります。