#CppUMockを使ってみたい
説明を読んでもCppUMockの使い方がよく分からなかったので実際にやってみた。
自分でモックを書いてもいいが公知の技術であるCppUMockを使うとオレオレ実装よりも他の人に理解してもらいやすいというメリットがあると思う。
https://cpputest.github.io/index.html
執筆時点のバージョンはCppUTest 3.8であった。
##単純な呼び出し検査
これは説明通りなので特にハマりどころはないと思われる。
#include "CppUTest/TestHarness.h"
#include "CppUTestExt/MockSupport.h"
TEST_GROUP(Sample)
{
void setup() {}
void teardown()
{
mock().clear();
}
};
// 製品コードを呼ぶ代わりにこの関数を呼ぶようにしてMockに記録する
void production()
{
mock().actualCall("production");
}
TEST(Sample, SimpleCall)
{
// ここで1回呼ばれる事を期待するよう設定している
mock().expectOneCall("production");
// このテストが成功する条件はこの関数が1回呼び出される事となる
production();
// テストの評価:ここでは関数が1回呼び出されていればテスト成功
mock().checkExpectations();
}
##戻り値がある関数の検査
製品コードからの戻り値をコントロールしたい場合などに使うことができる。呼び出す事を期待するときにandReturnValue(int value)
メソッドなどを使ってその関数の戻り値を制御することができ、戻り値はモック側のreturnIntValue()
メソッドなどに渡されて利用できる。型ごとに戻り値のバリエーションが用意されている。また、期待側で戻り値を明確に設定しなかった場合にデフォルトの戻り値をモック側で用意する方法も用意されている。例えばreturnIntValueOrDefault(int default_value)
など。自分としてはandReturnValue(Hogehoge)がreturnHogehogeValue()に渡されるという風に説明してくれたらわかりやすかったなと思うなど。あれ?書いてあった?
int intProduction()
{
return mock()
.actualCall("intProduction")
// andReturnValue(int)で設定された戻り値を受け取る
.returnIntValue();
}
TEST(Sample, ReturnValue)
{
int ret;
mock().expectOneCall("intProduction")
// 戻り値をここで制御することができる。
.andReturnValue(1);
ret = intProduction();
CHECK_EQUAL(1, ret);
mock().checkExpectations();
}
##パラメータのある関数の検査
パラメータを持つ関数のパラメータに期待値を設定することができる。これもパラメータの型ごとにメソッドが用意されている。
void parameterProduction(int prm)
{
mock()
.actualCall("parameterProduction")
.withIntParameter("prm", prm);
}
TEST(Sample, Parameter)
{
mock().expectOneCall("parameterProduction")
.withIntParameter("prm", 1);
parameterProduction(1);
mock().checkExpectations();
}
##オブジェクトを渡す?
これは使用例にすぎないと思う。最初の単純な呼び出しを間接的に使っているだけでやっていることは同じだと思う。
class ClassFromProductionCode
{
public:
virtual void importantFunction()
{
}
virtual ~ClassFromProductionCode() {}
};
class ClassFromProductionCodeMock : public ClassFromProductionCode
{
public:
virtual void importantFunction()
{
mock().actualCall("importantFunction");
}
virtual ~ClassFromProductionCodeMock() {}
};
TEST(Sample, Object)
{
mock().expectOneCall("importantFunction");
ClassFromProductionCode *obj = new ClassFromProductionCodeMock;
obj->importantFunction();
mock().checkExpectations();
delete obj;
}