前回こんなことを書いてみた。
それに近いことをやろうとするとこうなるのかなと思った。
骨子は以下の通り。
- 本来の関数定義がされている場所の実装を少し変更する。具体的には、
- モックする関数名を書き換える
- 本来の関数名をグローバル変数として定義し、その先を上記1の
書き換えた関数名
にする
- テスト内では、グローバル変数を駆使して、モックしたい関数をうまいこと入れ替える
具体的には以下参照。
main.go
package main
import "fmt"
func main() {
// ReturnFalse() はすなわち return_false() と同じ
fmt.Println(ReturnFalse())
}
funcs.go
package main
var ReturnFalse = return_false
/*
もともと ReturnFalse という定義を、あえてグローバル変数に格上げして
その先の関数に(ここでは) return_false という関数をセットする
*/
func return_false() bool {
return false
}
funcs_test.go
package main
import (
"testing"
)
func TestFiveHoursAgo(t *testing.T) {
/*
事実上のモック箇所
ReturnFalse を別定義の無名関数で上書きする
*/
ReturnFalse = func() bool { return true }
ret := ReturnFalse()
exp := true
if exp != ret {
t.Errorf("actual %v\nwant %v", ret, exp)
}
// ここでもとに戻す。実際には defer 処理でやればいい
ReturnFalse = return_false
}
実行するとこうなる。
% go test funcs.go funcs_test.go
ok command-line-arguments 0.007s
ただ毎回こんなことをするのは無理があるので、実際には難しい気がする。
ということで調べていると、withmock が良さそうなんだけど、moduleモードではちゃんと動いてくれないな・・・。