はじめに
Goでテストを書いているときにあるメソッド(ここではHogeと呼ぶことにします)を今実装しているservice層の処理で使っていて、テストを書く時にHogeを使うために用意する実データをDBに用意するのが非常に面倒だったので、Hoge自体をgomockで置換えようとしました。しかしここでHogeをgomockで差し替えると今回テストしたいservice層のメソッド(ここではFooと呼ぶことにします)までモック化されてしまうという場面に遭遇しました。(HogeとFooは同じservice packageでかつ同ファイルに定義されているメソッドです)何とかHogeだけgomockでダミーデータを返すモック差し替えて、Fooは実際のロジックを使うというやり方をみつけたのでそのやり方をこの記事にまとめたいと思います。
解決方法
gomockのDoAndReturnで実体をmockに差し込む
Hogeはgomockを使ってモック化して、Fooはgomock経由で実体を差し込むという方法があります。gomock経由で実体を差し込むためにはgomockに用意されているDoAndReturn
というメソッドを使用します。
func (c *Call) DoAndReturn(f interface{}) *Call
DoAndReturn declares the action to run when the call is matched. The return values from this function are returned by the mocked function 引用元:「GoDoc」
https://godoc.org/github.com/golang/mock/gomock#Call.DoAndReturn
DoAndReturn
を使うことでmockメソッドが呼ばれたときにここに定義した関数を実行して、その結果を返すことができます。つまりgomockに実体を差し込むことができるのです。かなり雑なコードですが、サンプルを一部書いておきました。
ctrl := gomock.NewController(t)
sampleMock := service.NewMockSample(ctrl)
sampleMock.EXPECT().Hoge.(gomock.Any()).Return("this is Hoge", nil).AnyTimes()
sampleMock.EXPECT().Foo(gomock.Any()).DoAndReturn(
func(arg string) string {
return service.NewSample().Foo(arg)
}).AnyTimes()
Fooの実体をgomockのFooに差し込んでいます。
参考文献: