テスト時のinterfaceに対するfake objectの作成にinterfaceの埋め込みを使う
過去の以下の記事の続き。
この方法はたまに使われていたりする。ただリンク先の記事ではinterfaceを実装したstruct(アプリで実際に利用しているstruct)を埋め込んでいる。
これはテスト中にはinterfaceを埋め込んだほうが良いかもしれないという話。
例
以下のようなインターフェイスがある。このインターフェイスはF()
とG()
の二つのメソッドを要求している。
type I interface { F() G() }
先程のインターフェイスIのうち、F()
だけに依存するコードのテストのfake objectは以下で十分。
type fake struct { I } func (f *fake) F() { fmt.Println("f") }
実際以下の様なコードはコンパイルできる。
func use(i I) { i.F() } func main() { fake := &fake{} use(fake) }
定義していなかったほうのメソッドが呼ばれた場合
先程のfake objectはF()
の利用のためにF()
だけを定義していた。実際にはG()
の実装が要求される場合にはnil dereference panicになる。
--- 00/main.go 2018-09-21 22:14:55.873712187 +0900 +++ 01/main.go 2018-09-21 22:15:15.050405975 +0900 @@ -18,7 +18,7 @@ } func use(i I) { - i.F() + i.G() } func main() {
初見では原因や修正箇所が分かりづらいかもしれない。
panic: runtime error: invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation code=0x1 addr=0x20 pc=0x48220e] goroutine 1 [running]: main.(*fake).G(0xc42000e1e0) <autogenerated>:1 +0x2e main.use(0x4c39e0, 0xc42000e1e0) VENV/individual-sandbox/daily/20180920/example_embed/01/main.go:21 +0x31 main.main() VENV/individual-sandbox/daily/20180920/example_embed/01/main.go:26 +0x3d exit status 2