2012年1月28日土曜日

Google Test を使ってみる - その3(テストケース)

Google Test シリーズ第3弾。

今回は、様々なテストの書き方を見てみたいと思います。

※ Google Test 関係の記事一覧はこちら
最も簡単なテスト
最も簡単なテストの作り方は以下になります。
TEST(CaseName, TestName)
{
    // ここにテストコード
}
テストフィクスチャ
テストフィクスチャを使うことで、テストリソースの共有が可能です。
class TestFix : public ::testing::Test
{
protected:
    std::vector data;

    virtual void SetUp()
    {
        printf("TestFix::SetUp\n");
        data.push_back(0);
        data.push_back(1);
        data.push_back(2);
    }
    virtual void TearDown()
    {
        printf("TestFix::TearDown\n");
    }
}:
TEST_F(TestFix, Test1)
{
    data.push_back(3);  // TestFix のメンバーにアクセス可能
    TEST_ASSERT_EQ(3, data.size());
}
TEST_F(TestFix, Test2)
{
    TEST_ASSERT_EQ(3, data.size());
}
TEST_F マクロの第一引数に、::testing::Test クラスを継承した
テストフィクスチャのクラス名を指定します。
このテストフィクスチャは、テスト毎に作られテスト開始前に SetUp 関数をコールします。
(テスト終了後には、TearDown をコール)

実行結果
[----------] 2 tests from TestFix
[ RUN      ] TestFix.Test1
TestFix::SetUp
main.cpp(21): error: Value of: data.size()
  Actual: 4
Expected: 3
TestFix::TearDown
[  FAILED  ] TestFix.Test1 (0 ms)
[ RUN      ] TestFix.Test2
TestFix::SetUp
TestFix::TearDown
[       OK ] TestFix.Test2 (0 ms)
[----------] 2 tests from TestFix (1 ms total)

さらに、テストケース名を分けたい場合は以下のようにも書けます。
class TestFix : public ::testing::Test

// 略 

TEST_F(TestFix, Test1)
{
    TEST_ASSERT_EQ(3, data.size());
}

typedef TestFix TestFix2; // 別名を定義する
TEST_F(TestFix2, Test1)
{
    TEST_ASSERT_EQ(3, data.size());
}
値をパラメータ化したテスト
値をパラメータ化することで、I/Oテストなどが書きやすくなります。
値のパラメータ化テストを使用する場合、まずは、::testing::TestWithParam クラスを継承したクラスを用意します。(このクラスは、::testing::Test も継承しているのでテストフィクスチャと同じように使用できます。)

次に、TEST_P マクロを使ってテストを作成します。
// template 引数にはパラメータの型を渡す
class TestP : public ::testing::TestWithParam {};

TEST_P(TestP, TestA)
{
   int param = GetParam(); // パラメータは GetParam 関数で取得できる。
   printf("%d\n", param);
}
これだけでは、まだテストは実行しません。
最後に、パラメータを与えてテストをインスタンス化します。
INSTANTIATE_TEST_CASE_P(InstantiationName, TestP
    , ::testing::Values(1, 3, 0)); // ここがパラメータ
パラメータの作成には、::testing::Values 以外に
Range, ValuesIn, Bool, Combine があります。

実行結果
[----------] 6 tests from InstantiationName/TestP
[ RUN      ] InstantiationName/TestP.TestA/0
1
[       OK ] InstantiationName/TestP.TestA/0 (0 ms)
[ RUN      ] InstantiationName/TestP.TestA/1
3
[       OK ] InstantiationName/TestP.TestA/1 (0 ms)
[ RUN      ] InstantiationName/TestP.TestA/2
0
[       OK ] InstantiationName/TestP.TestA/2 (0 ms)

型付けテスト
template クラスや関数のテストをしたいときに、便利なのが型付けテストです。
// 型を受け取る(T は型リストから渡される)
template<class T>
class TypedTest : public testing::Test {
};
// 型リスト
typedef ::testing::Types<int, float, double> TestTypes;
// 型リストとテストを関連づける
TYPED_TEST_CASE(TypedTest , TestTypes);

// テストを記述する
TYPED_TEST(TypedTest, Test1)
{
    TypeParam p = 0; // TypeParam で型を取れる
    // ここにテストを書く
}
型付けテストを使用するのに必要な準備は3つ。
  • フィクスチャクラステンプレート(TypedTest)
  • 型リスト(TestTypes)
  • 型リストとテストクラスの関連付け(TYPED_TEST_CASE)
この3つを用意したら、あとは TYPED_TEST マクロを使ってテストを書くだけです。

実行結果
[----------] 1 tests from TypedTest/0, where TypeParam = int
[ RUN      ] TypedTest/0.Test1
[       OK ] TypedTest/0.Test1 (0 ms)
[----------] 1 tests from TypedTest/0 (0 ms total)

[----------] 1 tests from TypedTest/1, where TypeParam = float
[ RUN      ] TypedTest/1.Test1
[       OK ] TypedTest/1.Test1 (0 ms)
[----------] 1 tests from TypedTest/1 (0 ms total)

[----------] 1 tests from TypedTest/2, where TypeParam = double
[ RUN      ] TypedTest/2.Test1
[       OK ] TypedTest/2.Test1 (0 ms)
[----------] 1 tests from TypedTest/2 (0 ms total)
型をパラメータ化したテスト
型付けテストと違い、テスト自体は型リストのことを知らなくて良いのが、大きな違いです。
あらかじめテストを書いておき、あとからインスタンス化できます。
さらに、インスタンス化は異なる型リストで複数つくることが可能です。
//
// test.h

template<class T>
class TypedTestP : public testing::Test {
};
// テストケースを設定
TYPED_TEST_CASE_P(TypedTestP);

// テストを記述する
TYPED_TEST_P(TypedTestP , Test1)
{
    TypeParam p = 0; // TypeParam で型を取れる
    // ここにテストを書く
}
TYPED_TEST_P(TypedTestP , Test2)
{
}

// テストケースにテストを登録する
REGISTER_TYPED_TEST_CASE_P(TypedTestP  // テストケース名
    , Test1, Test2, Test3);  // テスト名の列挙
これで、テストをする部分が完成です。
値をパラメータ化したテストと同様に、まだテストが実行されない状態です。)

あとは、好きなところで好きな型リストを与えてインスタンス化します。
// test.cpp
#include "test.h"

typedef ::testing::Types<int, char> TestTypes;
// インスタンス化
INSTANTIATE_TYPED_TEST_CASE_P(InstantiateName // このインスタンスの名前
    , TypedTestP // テストケース名
    , TestTypes); // 型リスト

typedef ::testing::Types<float, double> TestTypes2;
// 別の型リストでインスタンス化
INSTANTIATE_TYPED_TEST_CASE_P(Floating // このインスタンスの名前(同名はダメ)
    , TypedTestP // テストケース名
    , TestTypes2); // 型リスト


実行結果
[----------] 2 tests from InstantiateName/TypedTestP/0, where TypeParam = int
[ RUN      ] InstantiateName/TypedTestP/0.Test1
[       OK ] InstantiateName/TypedTestP/0.Test1 (0 ms)
[ RUN      ] InstantiateName/TypedTestP/0.Test2
[       OK ] InstantiateName/TypedTestP/0.Test2 (0 ms)
[----------] 2 tests from InstantiateName/TypedTestP/0 (0 ms total)

[----------] 2 tests from InstantiateName/TypedTestP/1, where TypeParam = char
[ RUN      ] InstantiateName/TypedTestP/1.Test1
[       OK ] InstantiateName/TypedTestP/1.Test1 (0 ms)
[ RUN      ] InstantiateName/TypedTestP/1.Test2
[       OK ] InstantiateName/TypedTestP/1.Test2 (0 ms)
[----------] 2 tests from InstantiateName/TypedTestP/1 (0 ms total)

[----------] 2 tests from Floating/TypedTestP/0, where TypeParam = float
[ RUN      ] Floating/TypedTestP/0.Test1
[       OK ] Floating/TypedTestP/0.Test1 (0 ms)
[ RUN      ] Floating/TypedTestP/0.Test2
[       OK ] Floating/TypedTestP/0.Test2 (0 ms)
[----------] 2 tests from Floating/TypedTestP/0 (0 ms total)

[----------] 2 tests from Floating/TypedTestP/1, where TypeParam = double
[ RUN      ] Floating/TypedTestP/1.Test1
[       OK ] Floating/TypedTestP/1.Test1 (0 ms)
[ RUN      ] Floating/TypedTestP/1.Test2
[       OK ] Floating/TypedTestP/1.Test2 (0 ms)
[----------] 2 tests from Floating/TypedTestP/1 (0 ms total)
最後に
ここで紹介した方法は gtest のほんの一部です。
より詳しいことは、マニュアルにわかりやすく書かれているので、そちらをご確認下さい。
日本語訳されたマニュアルはこちらです。

1 件のコメント:

  1. テストケースが決まったら、それに沿ってテストデータを用意しなければなりません。
    普段テストデータにコード値や区分値などがあります。それはテストケースの組み合わせパターンを決めます。
    データの組み合わせのパターンを決めてからテストケースを書くのも多いです。

    品質のよいテストをするために、品質用のよいデータを使わなければなりません。

    下記のソフトは大量データの組み合わせパターンの作成ができます
    またExcelで60種類以上の本番擬似テストデータを生成して、
    そのままExcelシートからOracleやMySQLなど複数のデータベースへ登録できます。
    大量のテストデータ自動生成にはとても便利です。

    ExcelDBTool(ExcelでDB検索更新データ作成)
    http://www.vector.co.jp/soft/winnt/business/se475115.html

    ExcelDevTool(エクセル機能拡張でパワーアップ)
    http://www.vector.co.jp/soft/winnt/business/se475869.html

    http://www.superdbtool.com

    返信削除