TL;DR
https://github.com/vektra/mockery のmock指定時の注意点。
- 同じ引数
- 返り値が場合によって異なる
の条件を満たすmockを使いまわす場合は On()
のメソッドチェーンで Times()
をつける。
それが難しければ t.Run
のなかで new
すること。
回数を指定しない場合 On()
の上書きが効かないので、最初にセットされた Return()
を返し続けることになる。
例
func TestHoge(t *testing.T) {
mockFoo := new(mocks.Foo)
mockBar := new(mocks.Bar)
t.Run("test - first", func(t *testing.T) {
mockFoo.On("FuncA", mock.Anything).Return(1)
mockBar.On("FuncB", 1).Return(1)
// テストコード
})
t.Run("test - second", func(t *testing.T) {
mockFoo.On("FuncA", mock.Anything).Return(2)
mockBar.On("FuncB", 2).Return(2)
// テストコード
})
}
( test - first
→ test - second
の順にテストが流れると想定する。)
上記のようなテストがあったとき、mockが返す値は以下のようになる。
mockFoo.FuncA | mockBar.FuncB | |
---|---|---|
test - first | 1 | 1 |
test - second | 1 | 2 |
原因は、モックが 同じ引数 で On()
を上書きできないため。
Return()
指定時にあらかじめ回数を指定されない限り、最初にセットされた Return()
をずっと返し続ける様子。
どちらのテスト内でも引数 mock.Anything
を渡されている FuncA
は test - second
の中でも1
を返している( test - first
でセットされたため)が、
t.Run()
の中で毎回違う引数を渡されている FuncB
はそれぞれ期待の値でモックできている。
対応策
呼び出し回数を指定する。 Times()
など。
回数を指定すると、その回数に到達したときに自動的にモックを解除してくれる。
ちなみに、指定の回数 < 実際に呼ばれた回数になるとPanicになる。
mock.AssertExpectations(t)
を指定しておくと、
実際に呼ばれた回数 < 指定の回数だったときにもエラーにできる。
これらもテストとして有効利用できるかも。
-
Once()
- 1回だけ呼ぶ
-
Twice()
- 2回だけ呼ぶ
-
Times(i int)
-
i
で指定した回数だけ呼ぶ。3回以上指定したい時はこれ
-
func TestHoge(t *testing.T) {
mockFoo := new(mocks.Foo)
mockBar := new(mocks.Bar)
t.Run("test - first", func(t *testing.T) {
mockFoo.On("FuncA", mock.Anything).Return(1).Once() // 1回
mockBar.On("FuncB", 1).Return(1).Once() // 1回
})
t.Run("test - second", func(t *testing.T) {
mockFoo.On("FuncA", mock.Anything).Return(2).Twice() // 2回
mockBar.On("FuncB", 2).Return(2).Times(3) // 3回
})
}
どうしても Times()
の指定が難しい場合は、 t.Run()
の中で毎回mockを作り直したほうが事故を防げる。