メモの日々


2009年05月26日(火) [長年日記]

  • 運動のため、ときどき家まで歩いて帰ってみている。1時間くらいで帰れる。
  • 暇は終了している。今はC++を使っています。

[c++][dev] Boost Test Library Unit Test Framework のサンプル

Boost Test Libraryに含まれているUnit Test Frameworkを使ったのでサンプルをメモ。

手元のBoostのバージョンは1.37、最新は1.39のようだ。

サンプルソース

test_main.cpp、vector_test1.cpp、vector_test2.cpp の3つのファイルを作った。

  • テストの構成は色々あるようだが、dynamic library variant方式にした。BOOST_TEST_DYN_LINK を define すればいいみたい。
  • dynamic library variant方式の場合は BOOST_TEST_MODULE を define すると main() が自動生成される。
  • include するヘッダは boost/test/unit_test.hpp。
  • テストケースは BOOST_AUTO_TEST_CASE() を使って書くのがよさそう。
  • 値の検査は BOOST_CHECK_EQUAL() や BOOST_REQUIRE_EQUAL() で行える。BOOST_CHECK_EQUAL() だと検査がfailedになった場合でもテストケースの処理は先へ進む。使える検査用のマクロ一覧はリファレンスにある。
  • setup, teardown 相当の処理は、「フィクスチャ」のコンストラクタとデストラクタで行う。下のサンプルではフィクスチャとして Fixture というクラスを作った。
  • テストケース内ではフィクスチャクラスのメンバ変数に直接アクセスできる。フィクスチャクラスを継承しているようだ。
  • フィクスチャを使うときは、Test suite level fixtureを使用するのがよさそう。BOOST_FIXTURE_TEST_SUITE() を使う。
  • テストケースやフィクスチャは無名(じゃなくてもいいけど)名前空間の中に書くのがよさそう。名前の衝突を気にしなくてよくなるので。
  • 全体的に文字列をほとんど与えられず、日本語を埋め込む余地があまりなさそうなのが残念。
// test_main.cpp
#define BOOST_TEST_MODULE "ここは日本語を書けそう"
#define BOOST_TEST_DYN_LINK
#include <boost/test/unit_test.hpp>
// vector_test1.cpp
#include <boost/test/unit_test.hpp>
#include <vector>

namespace {
    struct Fixture {
        std::vector<int> v;

        Fixture() {
            v.push_back(1);
        }
    };

    BOOST_FIXTURE_TEST_SUITE(my_suite, Fixture)

    BOOST_AUTO_TEST_CASE(add_element) {
        // Fixtureのメンバ変数 v を直接参照できる
        v.push_back(100);
        BOOST_CHECK_EQUAL(v.back(), 100);
        BOOST_CHECK_EQUAL(v.size(), 2);
    }

    BOOST_AUTO_TEST_CASE(remove_element) {
        v.pop_back();
        BOOST_CHECK_EQUAL(v.size(), 0);
    }

    BOOST_AUTO_TEST_SUITE_END()
}
// vector_test2.cpp
#include <boost/test/unit_test.hpp>
#include <vector>

namespace {
    struct Fixture {
        std::vector<int> v;

        Fixture() {
            v.push_back(1);
            v.push_back(2);
            v.push_back(3);
        }
    };

    BOOST_FIXTURE_TEST_SUITE(my_suite, Fixture)

    BOOST_AUTO_TEST_CASE(add_element) {
        v.push_back(100);
        BOOST_CHECK_EQUAL(v.back(), 100);
        BOOST_CHECK_EQUAL(v.size(), 4);
    }

    BOOST_AUTO_TEST_CASE(remove_element) {
        v.pop_back();
        BOOST_CHECK_EQUAL(v.back(), 2);

        // テストをわざと失敗させるてみる
        BOOST_CHECK_EQUAL(v.size(), 100);
        BOOST_REQUIRE_EQUAL(v.empty(), true); // これも実行される
        BOOST_CHECK_EQUAL(v[0], 100);         // これは実行されない
    }

    BOOST_AUTO_TEST_SUITE_END()
}

ビルド

次のようにしてビルドできる。

$ g++ -Wall -lboost_unit_test_framework-mt -o testrunner *.cpp

実行結果

実行結果は次の通り。

$ ./testrunner
Running 4 test cases...
vector_test2.cpp(29): error in "remove_element": check v.size() == 100 failed [2 != 100]
vector_test2.cpp(30): fatal error in "remove_element": critical check v.empty() == true failed [false != true]

*** 2 failures detected in test suite "ここは日本語を書けそう"

オプションを付けることで出力内容を変えられるが、気に入ったフォーマットが見当たらない。

$ ./testrunner --log_level=test_suite --report_level=detailed
Running 4 test cases...
Entering test suite "ここは日本語を書けそう"
Entering test suite "my_suite"
Entering test case "add_element"
Leaving test case "add_element"
Entering test case "remove_element"
vector_test2.cpp(29): error in "remove_element": check v.size() == 100 failed [2 != 100]
vector_test2.cpp(30): fatal error in "remove_element": critical check v.empty() == true failed [false != true]
Leaving test case "remove_element"
Entering test case "add_element"
Leaving test case "add_element"
Entering test case "remove_element"
Leaving test case "remove_element"
Leaving test suite "my_suite"
Leaving test suite "ここは日本語を書けそう"

Test suite "ここは日本語を書けそう" failed with:
  6 assertions out of 8 passed
  2 assertions out of 8 failed
  3 test cases out of 4 passed
  1 test case out of 4 failed
  1 test case out of 4 aborted

  Test suite "my_suite" failed with:
    6 assertions out of 8 passed
    2 assertions out of 8 failed
    3 test cases out of 4 passed
    1 test case out of 4 failed
    1 test case out of 4 aborted

    Test case "add_element" passed with:
      2 assertions out of 2 passed

    Test case "remove_element" aborted with:
      1 assertion out of 3 passed
      2 assertions out of 3 failed

    Test case "add_element" passed with:
      2 assertions out of 2 passed

    Test case "remove_element" passed with:
      1 assertion out of 1 passed

やること

  • 請求書
  • 請書