GoogleTestがどうやってテストを登録しているのか調べてみた.
TESTの展開
単純なテストは次のように書ける.
TEST(テストケース名, テスト名)
{
// テスト内容
}
このテストは,マクロが展開されて次のようなコードになる.
class テストケース名_テスト名_Test : public ::testing::Test
{
public:
テストケース名_テスト名_Test() {}
private:
virtual void TestBody();
static ::testing::TestInfo * const test_info_;
テストケース名_テスト名_Test(テストケース名_テスト名_Test const &) = delete;
void operator=(テストケース名_テスト名_Test const &) = delete;
};
::testing::TestInfo * const テストケース名_テスト名_Test::test_info_ = ::testing::internal::MaekAndRegisterTestInfo(
"テストケース名",
"テスト名",
0,
0,
::testing::internal::CodeLocation(ファイルパス, 行数),
(::testing::internal::GetTestTypeId()),
::testing::Test::SetUpTestCase,
::testing::Test::TearDownTestCase,
new ::testing::internal::TestFactoryImpl<テストケース名_テスト名_Test>
);
void テストケース名_テスト名_Test::TestBody()
{
// テスト内容
}
まず,テストケースとテスト名から新しいクラスが作られ,test_info_というstaticメンバ変数が用意される.このtest_info_を初期化する際に,MakeAndRegisterTestInfo()を呼び出すことで,テストを登録しているようだ.
そして,テストの内容は,生成されたクラスのメンバ関数TestBody()の本体として扱われる.
MakeAndRegisterTestInfoの概要
MakeAndRegisterTestInfoについて,もう少し詳しく見てみる.宣言は次のようになっている.
TestInfo* MakeAndRegisterTestInfo(
const char* test_case_name,
const char* name,
const char* type_param,
const char* value_param,
CodeLocation code_location,
TypeId fixture_class_id,
SetUpTestCaseFunc set_up_tc,
TearDownTestCaseFunc tear_down_tc,
TestFactoryBase* factory
)
仮引数の意味は次のようになっている.
- test_case_name
- テストケース名
- test_name
- テスト名
- type_param
- 調査中
- value_param
- 調査中
- code_location
- ファイルの位置とテスト開始行数
- fixture_class_id
- fixtureクラスのID.::testing::internal::GetTypeId<テストケース名>()で求める.
- set_up_tc
- テストケース開始前に呼び出される関数への関数ポインタ
- tear_down_tc
- テストケース終了後に呼び出される関数への関数ポインタ
- factory
- テストを生成するクラス
この関数は,実引数からTestInfoを生成し,::testing::UnitTestに登録する.実際には,::testing::internal::UnitTestImplに登録する.レポータによって切り替わるようだ.
この登録時に,テストケース別に登録するようになっており,初めて登録するテストケースの場合,自動的に新しいテストケース情報が登録されるようになっている.
テストの実行
テストの実行は,登録されたテストのTestBody()を実行しながら進んでいく.EXPECT_EQなどのアサート文を呼び出すと,
例外が有効であれば例外を,例外が無効であればWindowsの場合,Structured Exception Handling (SEH) を利用して,
問題を検出しているようだ.
まとめ
GoogleTestは,TESTマクロにより::testing::TestInfoのstatic変数を持ったクラスを生成し,その初期化を通してテストを登録している.
テストの本体は,::testing::Test::TestBody()の実装となり,実行時に呼び出される.