こないだの続き。こないだは、samplesフォルダにあるsample1_unittestをビルドして、単体テストできていることを確かめた。今回は、その他のsample2〜sample10を同様にビルドして、sample1〜sample6の中身を読み解いてみる。sample7〜sample10は、残念ながら私の能力が足りず読解を断念。
サンプルをすべてビルド
まず、READMEに従って、googletestのスタティックライブラリを作成する。
- $ gtest-1.7.0.zipを展開
- $ cd gtest-1.7.0
- $ mkdir lib
- $ g++ -isystem ../include -I../ -pthread -c ../src/gtest-all.cc
- $ ar -rv libgtest.a gtest-all.o
次にサンプルをビルドする。cd ../src/して、以下のスクリプトを作成して実行する。(Makefileでなくて申し訳ない)
#!/bin/sh # sample 1, 2, 4 for i in {1,2,4} do g++ -L../lib -isystem ../include -g -Wall -Wextra -pthread \ sample${i}.cc sample${i}_unittest.cc ../src/gtest_main.cc -lgtest -o sample${i}_unittest done # sample 3, 6, 7, 8 for i in {3,6,7,8} do g++ -L../lib -isystem ../include -g -Wall -Wextra -pthread \ sample${i}_unittest.cc ../src/gtest_main.cc -lgtest -o sample${i}_unittest done # sample 5 g++ -L../lib -isystem ../include -g -Wall -Wextra -pthread \ sample5_unittest.cc sample1.cc ../src/gtest_main.cc -lgtest -o sample5_unittest # sample 9, 10 for i in {9,10} do g++ -L../lib -isystem ../include -g -Wall -Wextra -pthread \ sample${i}_unittest.cc -lgtest -o sample${i}_unittest done
sample1_unittest
これは前回の記事で見たとおり。Cスタイルの非メンバ関数をテストするサンプル。
sample2_unittest
自作文字列クラスであるMyStringクラスの、publicな関数をテストするサンプル。
MyStringクラスはsample2.hとsample2.ccに実装されている。
class MyString { public: // publicな関数の例(コンストラクタ) MyString() : c_string_(NULL) {} … }
例えば、このコンストラクタをテストするテストケースは、sample2_unittest.ccで以下のように書かれている。
// Tests the default c'tor. TEST(MyString, DefaultConstructor) { const MyString s; EXPECT_STREQ(NULL, s.c_string()); EXPECT_EQ(0u, s.Length()); }
sample3_unittest
test fixture(テストフィクスチャ)と呼ばれる仕組みが登場する。test fixtureを使うと、いくつかのテストを行う前に、自動で条件を揃えることができる。
例を見てみる。sample3-inl.hでは、自作キュークラスが実装されている。sample3_unittest.ccはそのキューのテストを行っている。キューをテストするためにはキューに値をつっこまないとテストできないわけだが、テストケースごとに毎回値をつっこむのは非効率的である。そこでtest fixtureの出番となる。
test fixtureを使うためには、testing::Testクラスを継承したクラスを作成する。
class QueueTest : public testing::Test { protected: virtual void SetUp() { // テストケースの最初に毎回実行したいことを書く q1_.Enqueue(1); q2_.Enqueue(2); q2_.Enqueue(3); } virtual void TearDown() { // テストケースの最後に毎回実行したいことを書く // したいことがないならコメントアウトすればよい } // テストケースで使いたい便利関数を定義してもよい static int Double(int n) { return 2*n; }
TEST_Fマクロを使ってテストケースを作成すると、テストケースの冒頭にSetUp()が、テストケースの末尾にTearDown()が自動実行される。
TEST_F(QueueTest, DefaultConstructor) { // You can access data in the test fixture here. EXPECT_EQ(0u, q0_.Size()); }
test fixtureについての日本語の詳しい説明は入門ガイド — Google Test ドキュメント日本語訳を参照。
ちなみに、test fixtureは直訳で「試験装置」という意味らしい。
sample4_unittest
Increment()を呼ばれるたび内部変数をインクリメントするCounterクラスをテストするサンプル。テスト用マクロのEXPECT_EQ()内でメソッドを呼ぶと、このメソッドが評価されて副作用が起きますよ、ということを説明するためのサンプルらしい。
TEST(Counter, Increment) { Counter c; EXPECT_EQ(0, c.Increment()); EXPECT_EQ(1, c.Increment()); EXPECT_EQ(2, c.Increment()); }
sample5_unittest
継承を使って、少しずつ異なるtest fixtureを作る方法を説明するサンプル。このサンプルでは、QuickTestという、継承元となるスーパークラス(super fixture)を作成している。QuickTestでは、各テストが一定時間内に終わったかどうかを測定するコードがSetUp()とTearDown()に仕組まれている。
class QuickTest : public testing::Test { protected: virtual void SetUp() { start_time_ = time(NULL); } virtual void TearDown() { const time_t end_time = time(NULL); // 処理が5秒より多くかかるならばfailとする EXPECT_TRUE(end_time - start_time_ <= 5) << "The test took too long."; } time_t start_time_; };
QuickTestクラスは、IntegerFunctionTestクラスとQueueTestクラスとに継承される。IntegerFunctionTestクラスやQueueTestクラスをtest fixtureとしてテストケースを作ることで、そのテストが5秒以内に終わることをテストの条件に含めることができる。
sample6_unittest
このサンプルでは、ある抽象クラスを継承して作成した複数の具象クラスに対して、まとめてテストを行う方法が紹介されている。
1つ目の方法は、testing::Typesを用いた"typed test"(=型付けテスト?)。テストしたい型を、Types<と>の間に列挙する。
typedef Types<OnTheFlyPrimeTable, PreCalculatedPrimeTable> Implementations; TYPED_TEST_CASE(PrimeTableTest, Implementations);
2つ目の方法は、"type-parameterized test"(=型をパラメータ化したテスト?)。正直よく分からない…
sample6を理解するためには、ブログズミ: Google Test を使ってみる - その3(テストケース)を読む方が良いと思う。