エンジニアのソフトウェア的愛情

または私は如何にして心配するのを止めてプログラムを・愛する・ようになったか

その5:前処理・後処理のあるテスト

各々のテストで同様の前処理や後処理がある場合、テストケース単位で設定することができます。


まず、::testing::Testの派生クラスとしてテストケース名のクラスを定義します。そしてこのクラスに前処理が必要であればSetUp関数を、後処理が必要であればTearDown関数を定義します。これらはpublicprotectedで定義する必要があります。

class QueueTest : public ::testing::Test
{
public:
    void SetUp()
    {
        // 前処理
    }

    void TearDown()
    {
        // 後処理
    }
};


これらの処理を含んだテストを定義するにはTESTマクロの代わりにTEST_Fマクロを使用します。そしてテストケースには上記で定義したクラス名を記述します。

TEST_Fマクロで定義されたテストは、テストが実行される前にSetUp関数が呼び出され、テスト終了後にTearDown関数が呼び出されます。また、データメンバが定義されている場合、テストの中からそれらにアクセスすることもできます。データメンバも同様にpublicprotectedで宣言されていなければなりません。

TEST_F(QueueTest, Test1)
{
    // テスト内容
}


実際に前処理、後処理を利用したテストの例です。それぞれの処理が実行されていることがわかるように、メッセージを出力するようにしています。
また、データメンバqueue_にアクセスしていることに注意してください。

#include <gtest/gtest.h>
#include <vector>
#include <iostream>

typedef std::vector<int> Queue;

class QueueTest : public ::testing::Test
{
protected:
    void SetUp()
    {
        std::cout << "QueueTest::SetUp" << std::endl;
        queue_.push_back(1);
        queue_.push_back(2);
        queue_.push_back(3);
    }

    void TearDown()
    {
        std::cout << "QueueTest::TearDown" << std::endl;
    }

    Queue queue_;
};

TEST_F(QueueTest, Test1)
{
    ASSERT_EQ(3u, queue_.size());
}

TEST_F(QueueTest, Test2)
{
    ASSERT_EQ(3u, queue_.size());
}

int main(int argc, char* argv[])
{
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}


実行結果。

[==========] Running 2 tests from 1 test case.
[----------] Global test environment set-up.
[----------] 2 tests from QueueTest
[ RUN      ] QueueTest.Test1
QueueTest::SetUp
QueueTest::TearDown
[       OK ] QueueTest.Test1
[ RUN      ] QueueTest.Test2
QueueTest::SetUp
QueueTest::TearDown
[       OK ] QueueTest.Test2
[----------] Global test environment tear-down
[==========] 2 tests from 1 test case ran.
[  PASSED  ] 2 tests.

「コンストラクタ/デストラクタとSetUp/TearDownの、どちらを使うべきか」

ここにも書かれているように、SetUp関数、TearDown関数の代わりにコンストラクタ、デストラクタを利用してもほぼ同じことができます。実際、前処理後処理の実行で問題が発生しない場合には、コンストラクタとデストラクタを利用しても同じことができます。
ですが次のような場合、SetUp関数とTearDown関数を使う利点があります。

  • デストラクタは例外を送出することはできません。テストの後処理で例外が送出される可能性がある場合、TearDown関数であれば例外を処理することができます。
  • SetUp関数内、TearDown関数内でアサーションマクロを使うことができます。
  • コンストラクタ内、デストラクタ内では仮想関数は使えません。仮想関数を使いたい場合にSetUp関数、TearDwon関数を利用できます。