2011年6月21日火曜日

macro trick in googletest

googletestでは、テストケースはこう書くわけ。
#include <gtest/gtest.h>

TEST(SampleTestCase, TestFunc) {
    EXPECT_TRUE(true);
}
C++な割にはスマート。で、なんで、こんなことができるのか。その仕組みを追ってみた。まずは、TEST()マクロ。

include/gtest/gtest.h:
#define TEST(test_case_name, test_name) \
  GTEST_TEST_(test_case_name, test_name, \
              ::testing::Test,\
              ::testing::internal::GetTestTypeId())
ほむ。次はGTEST_TEST_()マクロ。

include/gtest/internal/gtest-internal.h(抜粋):
#define GTEST_TEST_(test_case_name, test_name, parent_class, parent_id)\
class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\
 public:\
  GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {}\
 private:\
  virtual void TestBody();\
};\
\
void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody()
ほむほむ。GTEST_TEST_CLASS_NAME_()マクロは、test_case_nameとtest_nameを繋げて重複しないクラス名を生成する。上の例だと SampleTestCase_TestFunc_Test となる。最後の行は TestBody() のシグニチャだけ置いて、マクロに続くブロックが TestBody() の実装となるようになっているわけだ。

ちなみに、親クラスとなる ::testing::Test は include/gtest/gtest.h で定義されている。
include/gtest/gtest.h(抜粋):
class Test {
 protected:
  virtual void SetUp();
  virtual void TearDown();
 private:
  virtual void TestBody() = 0;
};
ほむほむほむ。予想どおり。

まとめ

最後に始めに出した例と、展開されたあとのイメージを載せておく。

展開前:
TEST(SampleTestCase, TestFunc) {
    EXPECT_TRUE(true);
}

展開後:
class SampleTestCase_TestFunc_Test : public ::testing::Test {
 public:
  SampleTestCase_TestFunc_Test() {}
 private:
  virtual void TestBody();
};

void SampleTestCase_TestFunc_Test::TestBody() {
    EXPECT_TRUE(true);
}
なるほどねぇ。