こんにちは。インサイトテクノロジー 札幌R&Dセンターの中井です。
担当しているプロジェクトでは、C++ユニットテストで使うモックライブラリとしてGoogle Mockを採用しているのですが、ちょっとしたことにひっかかることがしばしばありました。本記事では、これまでに私がひっかかったポイントを紹介します。
Google Mockの使い方に関しては、以下のページを参照してください。
興味がないメソッドの呼び出し
何もExpectationが設定されていないメソッドが呼び出された場合、エラーにはならず、警告が表示される一方で、何らかのExpectationを設定している場合、それにマッチしない呼び出しはエラーとなります。
そのため、あるメソッドの全ての呼び出しに興味がない場合、Expectationを設定すべきではないのですが、特定の呼び出しには興味があり、その呼び出しとマッチするExpectationを設定する際には、それ以外の興味がない呼び出しに対してもExpectationを設定しなければなりません。
呼び出し順序の制約とマッチング順序
Expectationとのマッチングは新しく定義された方から順に行われることを意識しないと、呼び出し順序の制約が意図したものより過剰になってしまう場合があります。
例えば、以下のようにExpectationを設定した場合を考えます。
::testing::Sequence s1, s2;
EXPECT_CALL(hoge, A())
.InSequence(s1, s2);
EXPECT_CALL(hoge, B())
.InSequence(s1);
EXPECT_CALL(hoge, C())
.InSequence(s1);
EXPECT_CALL(hoge, B())
.InSequence(s2);
EXPECT_CALL(hoge, D())
.InSequence(s2);
これらの定義による呼び出し順序の制約は、以下のDAG:
+---> B ---> C (s1)
|
A ---|
|
+---> B ---> D (s2)
で表され、一見するとA → B → C → B → Dといった順序で呼び出しても問題なさそうに見えます。しかし、実際にはBの呼び出しが新しく定義されたs2
の方からマッチするため、Cの呼び出しでエラーとなります。
呼び出し順序の制約と”sticky”なExpectation
デフォルトでは、メソッドを呼び出した回数がExpectationの上限に達した後でも、そのExpectationはマッチングの対象(アクティブ)のままです。この”sticky”な動作が無効になるケースとして、RetiresOnSaturation()
を指定した場合以外に、DAGのパス(シーケンス)に並んだ場合がありますが、後者においてExpectationが非アクティブになるのは、後続のExpectationがマッチした時点です。このことから、リーフとなるExpectationは依然としてstickyであることも注意が必要です。
EXPECT_CALL(hoge, A());
EXPECT_CALL(hoge, B())
.RetiresOnSaturation();
::testing::Sequence s;
EXPECT_CALL(hoge, C())
.InSequence(s);
EXPECT_CALL(hoge, D())
.InSequence(s);
hoge.A(); // Aはアクティブなまま
hoge.B(); // Bは非アクティブになる
hoge.C(); // Cはまだアクティブ
hoge.D(); // Cは非アクティブになる、Dはアクティブなまま
operatorのモック化
operatorを直接モック化することはできません。モック化するためには、通常のメソッドをoperatorでラップし、ラップされたメソッドをモック化する必要があります。
参考:
https://github.com/google/googletest/issues/1080
https://stackoverflow.com/questions/6492664/how-to-create-a-mock-class-with-operator
備考
Google Mock ドキュメント日本語訳 超入門編では、
分からないコンパイルエラーが出たら, Google Mock Doctor を試してください
と書かれていますが、原文にはそのような記述はなく、Google Mock Doctorは既に削除されているようです。
おわりに
本記事で紹介したポイントはほとんどドキュメントに書いてあり、言ってしまえば当たり前の内容ではありますが、エラーにはまっている最中だと、なかなか気づけないこともあるかもしれません。そのような時に、本記事が皆さんのお役に立てば幸いです。