goのmock使用中に「panic: reflect: NumIn of non-func type...」が起きた

環境

状況 ※ダメなコード例は面倒なので省略

  • mockを使ったテスト実施中に以下のようなエラーに遭遇する
panic: reflect: NumIn of non-func type *hoge.Huga [recovered]
    panic: reflect: NumIn of non-func type *hoge.Huga
  • stacktrace
goroutine 7 [running]:
testing.tRunner.func1.2(0x17e99c0, 0xc0002648c0)
    /Users/piyo/.anyenv/envs/goenv/versions/1.16.6/src/testing/testing.go:1143 +0x585
testing.tRunner.func1(0xc000224a80)
    /Users/piyo/.anyenv/envs/goenv/versions/1.16.6/src/testing/testing.go:1146 +0x3c8
panic(0x17e99c0, 0xc0002648c0)
    /Users/piyo/.anyenv/envs/goenv/versions/1.16.6/src/runtime/panic.go:971 +0x4c7
reflect.(*rtype).NumIn(0x18054e0, 0x0)
    /Users/piyo/.anyenv/envs/goenv/versions/1.16.6/src/reflect/type.go:984 +0x109
github.com/golang/mock/gomock.(*Call).DoAndReturn.func1(0xc000264840, 0x1, 0x1, 0x0, 0x0, 0x0)
    /Users/piyo/go/pkg/mod/github.com/golang/mock@v1.6.0/gomock/call.go:119 +0x166
(後略)

NumInとは?

  • reflect/type.goに記述あり。
NumIn returns a function type's input parameter count.
It panics if the type's Kind is not Func.

(関数の引数の個数を返す。関数じゃないものに対してこのメソッドが呼ばれるとpanicが起きる)

つまるところの原因

DoAndReturnのメソッドの使い方が誤っていた(構造体(*hoge.Huga)を渡していました)

  • DoAndReturnの使い方
DoAndReturn declares the action to run when the call is matched. The return values from this function are returned by the mocked function. It takes an interface{} argument to support n-arity functions.

(要約:モック対象の処理が呼ばれた時に実行してほしい関数を書く。モック対象の処理はその関数の戻り値を返却してくれる)

DoAndReturnメソッドは、n-arity functionのサポートのため、つまり関数の引数の個数が何個でも大丈夫なようにinterface型を引数として受け取れるようになっています。そのため、関数ではないものを渡したとしてもコンパイルエラーにはならず実行時にpanicが起こるようになっています。

参考

zenn.dev

感想(自戒)

  • 改めてエラーメッセージを読むと、初めから分かりやすく書いてあったんだなあと反省・・・(「NumInって何者!?」ってなって思考停止しておりました)
  • panicが発生した時はスタックトレースにきちんと目を通すのが大事
  • スタックトレースよくわからん、ってなったら(僕)デバッグを活用してどこで起きているのかを突き止めるのが大事
  • メソッドの使い方の説明文が英語だとしてもせいぜい数行、丁寧に読もう