まぎらわしい仲間たち #42

公開日: 2012-11-23


テストを書くときに使えるテクニックのひとつにモックというものがある。本物のオブジェクトの代わりにモックを差し込んで、期待通りに関数が呼ばれるか調べる、なんてテストを書くのに使える。たとえば、リクエストを処理したらメールを送る、なんていうコードをテストする場合、ユニットテストで本当にメールを送るわけにもいかないから、 MockMailer なんてモックを差し込んで、Send() 関数が正しい引数で呼ばれることをチェックする、なんていうテストが書ける。

というわけで、モックというものはなかなか便利なんだけど、モックと似たようなものがいろいろあってややこしい。"TotT: Friends You Can Depend On" [1] という記事ではダミー、スタブ、モック、スパイ、フェイクの違いが紹介されている。

大雑把にいうと、ダミーは値はどうでもいいけど、とりあえず何かをつっこみたいときに使うもの。スタブはハードコードした値を返すだけのもの。モックは関数が期待通りに呼ばれるかをテストするために使うもの。 スパイはモックと似ているけど状態を記録してテストするために使うもの。フェイクは本物の実装の代わりに単純な偽の実装を提供するもの。

これらは適材適所で使い分けるのが望ましいのだけど、どれも似たような概念なので、正しいものを選ぶのはなかなか難しい。で、この中でモックに関しては googlemock [2] (C++) のようなモックフレームワークがあって、これらを使うと結構凝ったことがいろいろできる。たとえば、関数が呼ばれたときに、単純に値を返すだけじゃなくて、ロジックを実行して、パラメータに基づいて値を計算して返す、なんてことができたりする。

で、こんな機能を使ってごちゃごちゃ書いていると、これ、モックじゃなくてフェイクなんじゃないの?なんてことが起きる。つい先日もそういうことがあって、複雑な挙動を定義していたモックを、モックフレームワークなしでフェイクとして作り直したら、コードが非常にわかりやすくなった。

これに気をよくして、既存のモックをチェックしてみたところ、関数呼び出しの期待 (expectation) が何もセットされていないモックがあった。じゃあ何に使われているかというと、別のオブジェクトを作るために必要なパラメータの一つとして使われているだけであった。

じゃあこれはモックじゃなくてダミーなんじゃないの、と思って同僚に相談したところ、 int を返す関数なんかは適当に 0 を返さないといけないし、これはハードコードした値を返すんだから、スタブなんじゃないか、ということになった。

とりあえず、Stubなんとかという名前のクラスを作ってコードレビューに投げたところ、同じ同僚から、いや、やっぱりこれはダミーだよ、というコメントが返ってきた。ううむ、まあたしかにそうかも、ということで Dummyなんとかに名前を変更。

が、チェックインしてからも、なんだかもやもやしていて、こういう何もしないオブジェクトって null オブジェクトとか呼ばれるんじゃなかったっけ、なんてことをぼんやり考えていると、 すごいことをひらめいた。そもそもこのオブジェクトはまったく使われていないんだから、ダミーのオブジェクトを作って渡す必要はなくて、コンストラクタには NULL でも渡しとけばいいんじゃないか。

で、実際にやってみたら、NULLを渡すだけでテストはあっけなく通った。つい先ほど導入された Dummyなんとかクラスは次のパッチで消され、NULL だけが残った。これはモックか?スタブだ、いやダミーだ、なんてがんばって議論していたのは一体なんだったのだろうか。

[1] http://googletesting.blogspot.jp/2008/06/tott-friends-you-can-depend-on.html
[2] http://code.google.com/p/googlemock/

Satoru Takabayashi