google mockで快適テスト生活

googleにより公開されているgoogle mockが使いやすかったので使い方紹介。

http://code.google.com/p/googlemock/
から落としてペペっと入れましょう。

使いたいシーンとしては、充分モジュール化されたオブジェクト指向プログラム中で

int main(){
  A a;
  B b;
  func(&a, &b);  // a->hoge(1)  と  b->fuga(2,3) が呼ばれて欲しい!
}

この様に特定の関数が狙った通りの動作をして欲しい(というか、その動作をすることを仕様化したい場合)

#include <gtest/gtest.h>
#include <gmock/gmock.h>
class mock_A{
public:
  MOCK_METHOD1(hoge,void(int));  // void hoge(int);と同義
};
class mock_B{
public:
  MOCK_METHOD2(fuga,void(int,int));  // void fuga(int,int);と同義
};

と書いて予め呼び出すシグネチャを定義しておき、gtestのテスト本体で

TEST(func, will_call_hoge_and_fuga){
  mock_A a;
  mock_B b;

  // 呼ばれるべき関数を規定
  EXPECT_CALL(a, hoge(1));
  EXPECT_CALL(b, fuga(1,2));

  // 実際に関数を呼んでみる
  func(&a, &b); // a->hoge(1), b->fuga(1,2)の両方が呼ばれたらテスト成功
}

のように書く事でテストを作れます。
ノリとしてはジョジョ2部の「次にお前は○○と言う!!」みたいな感じですね。


関数がそもそもA,Bに対応しているのに対し、mock_Aとmock_Bを引数に取らせてテストをすることになるため
funcはtemplateで記述する必要があります。

template <typename A, typename B>
void func(A* a, B* b){
   ...
}

templateだとコンパイル時間が膨れ上がるようになるので継承でどうにかすることもできます。

// Aもmock_Aもこれらのクラスを継承する。
struct base_A{
  virtual void hoge(int) = 0;
  ......
};
struct base_B{
  virtual void fuga(int,int) = 0;
  ......
};

// baseをターゲットにする
void func(base_A* a, base_B* b);

動的にディスパッチされるのでコンパイル時の負担が減る…はずです。


実際にそれなりに便利に使ってるコードは
http://github.com/kumagi/skipgraph/blob/master/logic_test.cc
で公開しています。
skip graphの各ノードの挙動を規定してその動作の通りになっている事をチェックさせています。
まったく同一のコードを実際のノード上で別のtemplate引数で展開するので安心です。

以下、細かいTips

続きを読む