Google Testでデータドリブンテスト
- Google TestのValue-Parameterized Tests
testing::TestWithParam
、TEST_P
、INSTANTIATE_TEST_SUITE_P
を使う
他の (言語の) テスティングフレームワークで、同一のテストを異なるデータで実行するデータドリブンテストの機能があって、これGoogle Testでも無いんかいな、と調べたところあった。
Google Testでは「Value-Parameterized Tests」として説明されている。説明内に「data-driven testing」って記述があるので、検索すれば引っかかる。
Value-Parameterized Tests
使用する機能さえ把握してしまえば難しくない。シンプルに書けるようにうまく設計されてる。
// テストデータクラス struct MyTestParam { int v1; int v2; int ok_v; MyTestParam( const int v1, const int v2, const int ok_v ) : v1(v1), v2(v2), ok_v(ok_v) { } }; // TestWithParamにテストデータのクラスを渡して、継承する class MyTest : public testing::TestWithParam<MyTestParam> { }; // TEST_Pでテストを書く // GetParamでテストデータクラスのインスタンスを得る TEST_P(MyTest, test) { const auto p = GetParam(); EXPECT_EQ(p.v1 + p.v2, p.ok_v); } // データをインスタンス化して、テストを作る INSTANTIATE_TEST_SUITE_P(OkTest, MyTest, testing::Values( MyTestParam(1, 2, 3), MyTestParam(2, 3, 5) ) );
実行結果。
Note: Google Test filter = */MyTest.* [==========] Running 2 tests from 1 test suite. [----------] Global test environment set-up. [----------] 2 tests from OkTest/MyTest [ RUN ] OkTest/MyTest.test/0 [ OK ] OkTest/MyTest.test/0 (0 ms) [ RUN ] OkTest/MyTest.test/1 [ OK ] OkTest/MyTest.test/1 (0 ms) [----------] 2 tests from OkTest/MyTest (2 ms total) [----------] Global test environment tear-down [==========] 2 tests from 1 test suite ran. (3 ms total) [ PASSED ] 2 tests.
OkTest/MyTest.test/0
といった感じで出力される。この文字列でフィルタ出来るので、--gtest_filter=*/MyTest.*/0
で、1つ目のデータだけで実行できる。
テストデータに名前を付ける (出力する)
/0
、/1
の部分の文字列を置き換える。仕組み上任意の文字列...とまではできないのだけど、ある程度読みやすくなる。
簡単なのがテストデータに対してoperator<<
を用意してあげる方法。合わせて、INSTANTIATE_TEST_SUITE_P
の最後に、testing::PrintToStringParamName()
を渡す。
struct MyTestParam { std::string desc; // 追加 int v1; int v2; int ok_v; MyTestParam( const std::string & desc, // こっちも更新 const int v1, const int v2, const int ok_v ) : desc(desc), v1(v1), v2(v2), ok_v(ok_v) { } }; // operator<<を作って、単純にdescを返す std::ostream & operator<<(std::ostream & stream, const MyTestParam & p) { return stream << p.desc; } class MyTest : public testing::TestWithParam<MyTestParam> { }; TEST_P(MyTest, test) { const auto p = GetParam(); EXPECT_EQ(p.v1 + p.v2, p.ok_v); } INSTANTIATE_TEST_SUITE_P(OkTest, MyTest, testing::Values( MyTestParam( "1p2eq3", // テスト名をつける 1, 2, 3 )), testing::PrintToStringParamName() // 追加 );
実行結果。/0
だったところに指定したテスト名が出力されている。
Note: Google Test filter = */MyTest.* [==========] Running 1 test from 1 test suite. [----------] Global test environment set-up. [----------] 1 test from OkTest/MyTest [ RUN ] OkTest/MyTest.test/1p2eq3 [ OK ] OkTest/MyTest.test/1p2eq3 (0 ms) [----------] 1 test from OkTest/MyTest (1 ms total) [----------] Global test environment tear-down [==========] 1 test from 1 test suite ran. (2 ms total) [ PASSED ] 1 test.
テストデータだけだと何を狙ったデータなのかの情報がロストする。コメントでもいいけど、なんとなく把握できるテスト名を適当につけとくと、コード的にもテスト結果的にも内容を把握する手助けになる。