既存のmethodを壊さずに内部のmethodを差し替えて実行したい
はじめに
例えば、以下のような状況で M.F0()
を呼びたい。しかしその内部で呼ばれる m.f()
は呼んでほしくない場合。
type M struct { } func (m *M) F0() error { // do something return m.f() } func (m *M) F1() error { // do something return m.f() } func (m *M) f() error { // この処理を呼びたくない panic("don't call!!1") }
通常のアプリケーションコードとして結合された状態で呼ばれる分には何ら問題無いコードも、テスト中では呼び出したくない場合がある。
例えば、 M.f()
が外部のリソースに依存するような処理だった場合など、テスト中では呼び出したくない。
もちろん現状で以下の呼び出しはpanicする。
m.F0() // panic m.F1() // panic
この時、公開された関数である M.F0()
, M.F1()
の内部で呼ばれる M.f()
の挙動を差し替えたい。
単純なembedではダメ
以下はどう考えてもダメ。
type mockM struct { *M } func (m *M) f() error { // こちらが呼ばれてくれると嬉しいけれど }
embedにより書き換えたつもりになっているのかもしれないけれど。mockM.F0()
の呼び出しで、実質呼ばれるのは内部の M.F0()
。
その為、結局 M.f()
の方が呼ばれてしまう。
内部の部分を切り分けてembedするのが無難そう
内部の部分を切り分けてembedするのが無難そう。型定義を以下の様に変える。
type mClient interface { f() error } type M struct { mClient }
内部で利用するclientのinterfaceを定義。 デフォルトではactualMClientの方を利用し、テストの時などはmockedMClientの方を利用する。
type actualMClient struct { } func (c *actualMailerClient) f() error { // この処理を呼びたくない } type mockedMClient struct { } func (c *mockedMClient) f() error { // こちらが呼ばれてくれると嬉しい }
以下のような関数があるとうれしいかも?
func NewM() *M{ client := actualMClient{} m := M{mClient: &client} return &m }