Typed Testsがいいかんじ

googletestをつかっているのですが、Typed Testsがいいかんじですね。いっしょに仕事をしている先輩がみつけて導入しだしたんですが、ほんといいです。(余談ですが、googletest自身、KKD氏も「筋がいい」と絶賛していました)

Typed Testsというのは、C++のテンプレートを使って複数のクラスのテストをまとめて記述ができるようなもの。
たとえば、vectorとlistのテストをしたいとします。この場合、フィクスチャ用のクラスをテンプレートで記述します。

template <typename T> class ContainerTest : public ::testing::Test {
    public:
        T target;
        int expect;;
        void SetUp(){};
};

今回は、インスタンス変数にターゲットとなるクラスのインスタンスとintの変数、SetUp関数を定義します。(SetUp()とTearDown()とつけた関数は、テスト実行時にsetup/teardownとして自動的に実行してくれます。)

次に、今回テスト対象とするクラスの宣言をします。

typedef ::testing::Types<std::list<int>, std::vector<int> > ContainerTypes;
TYPED_TEST_CASE(ContainerTest, ContainerTypes);

testing::Typesのテンプレート引数にテスト対象クラスを追加していき、TYPED_TEST_CASEで、テストとtesting::Tyepsを結びつけます。

次に、listとvectorのSetUp()を定義します。今回はSetUp()の説明をするために無理矢理ここでテストの期待値をいれますが、ふつうはこんなことしないでしょう。

template <> void ContainerTest<std::list<int> >::SetUp() {
    this->expect =1;
}

template <> void ContainerTest<std::vector<int> >::SetUp() {
    this->expect =2;
}

あとはテストを書くのみ

TYPED_TEST(ContainerTest, iterate) {
    this->target.push_back(this->expect);
    typename TypeParam::iterator itr = this->target.begin();
    typename TypeParam::iterator tail = this->target.end();
    while (itr != tail) {
        ASSERT_EQ(*itr, this->expect);
        ++itr;
    }
}

すごく簡単。テスト中にテストに使用するクラスは"TypeParam"でとれます。

今回のテスト全部はこちら。http://gist.github.com/329152

実行するとこんな感じで、2つのクラスで実行されているのがわかります。

[==========] Running 2 tests from 2 test cases.
[----------] Global test environment set-up.
[----------] 1 test from ContainerTest/0, where TypeParam = std::list<int, std::allocator<int> >
[ RUN      ] ContainerTest/0.iterate
[       OK ] ContainerTest/0.iterate (0 ms)
[----------] 1 test from ContainerTest/0 (0 ms total)

[----------] 1 test from ContainerTest/1, where TypeParam = std::vector<int, std::allocator<int> >
[ RUN      ] ContainerTest/1.iterate
[       OK ] ContainerTest/1.iterate (0 ms)
[----------] 1 test from ContainerTest/1 (0 ms total)

[----------] Global test environment tear-down
[==========] 2 tests from 2 test cases ran. (3 ms total)
[  PASSED  ] 2 tests.

ほんとC++はテンプレートのおかげで、型があるとはいえ楽に記述できますね。メソッド名さえあっていれば、こんなテストの書きかたもできるわけですし。あとは、文字列でevalがあると(ry (まぁ、マクロつかえってことかもしれませんが)