go でモックを使うテストを書く
Goでモックを使うテストを書く時に利用するgomockについて簡単に整理しておく
使い方
大まかに3ステップ
- Install
- Generate
- Test
Install
テストの際に使うパッケージとGenerateコマンドのためのパッケージをそれぞれインストール
go get github.com/golang/mock/gomock
go install github.com/golang/mock/mockgen
Generate
source mode
と reflect mode
の2種類の使い方がある
source mode
ソースファイルを指定
mockgen -source={filepath} [options]
-destination
を指定しないと標準出力に出力される
reflect mode
Import pathと対象のシンボルを指定
mockgen {import path} {symbol[,...]}
- 複数のシンボルを指定する際はカンマ区切り指定
reflect mode
は reflection によって interface を理解するプログラムをビルドして mock を生成するらしいが、イマイチ違いは理解できてない(単純なケースならsource mode
で十分とある)
Test
READMEには Mocks と Stubs の2通りの使い方がある
とはいえ、使い方はほぼ同じなのでここではMockの方だけメモを残しておく
テストの中で登場する Controller
は、 Mock
で起きたことを監視する役割を持つと思っておけば良い
type Foo interface {
Bar(x int) int
}
func SUT(f Foo) {
// ...
}
func TestFoo(t *testing.T) {
ctrl := gomock.NewController(t)
// Assert that Bar() is invoked.
defer ctrl.Finish()
m := NewMockFoo(ctrl)
// Asserts that the first and only call to Bar() is passed 99.
// Anything else will fail.
m.
EXPECT().
Bar(gomock.Eq(99)).
Return(101)
SUT(m)
}
上からざっくり解説
- mockに渡すための Controller を生成する
- 最後に Controller の
Finish()
を呼ぶことで、Mock に期待したメソッド呼び出しのチェックをする - Mockに対して
EXPECT()
の後に、呼ばれることが期待される関数と引数を指定する - Mockに返して欲しい返り値を指定する
その他メモ
-
Mockが用意した
EXPECT()
メソッドが全て大文字なのは、 interface に定義されるかもしれないExpect()
などとの名前衝突を避けるため -
上記の例ではMockに対して
Bar
が引数1つ(99
)で呼び出されることを期待している -
引数のMatcherはいくつか種類があるが、例えば
Bar(99)
とそのまま値を渡してもgomock 側でよしなにBar(gomock.Eq(99)
と解釈してくれる -
Matcher は自作できる
順序について
EXPECT()
を複数書いた場合、何もしなければ呼び出し順序までは期待できない。
順序を指定したい場合は After
か InOrder
を使う
# Bar1 -> Bar2の順に呼び出されることを期待する
gomock.InOrder(
m.EXPECT().Bar1(99),
m.EXPECT().Bar2(100),
)