2012年12月27日木曜日

Google Test ユーザーが Boost.Test を使ってみた (補足)

この記事は、C++ Advent Calendar 2012: 17日目「Google Test ユーザーが Boost.Test を使ってみた」の補足記事になります。

本編では書ききれなかったことや、訂正なども含めて補足をしたいと思います。

値をパラメータ化したテスト
Boost.Test でも使えます。リファレンスはこちらです。

(Boost.Test Example)
#include <boost/test/included/unit_test.hpp>
#include <boost/test/parameterized_test.hpp>
using namespace boost::unit_test;

//____________________________________________________________________________//

void free_test_function( int i )
{
    BOOST_CHECK( i < 4 /* test assertion */ );
}

//____________________________________________________________________________//

test_suite*
init_unit_test_suite( int argc, char* argv[] )
{
    int params[] = { 1, 2, 3, 4, 5 };

    framework::master_test_suite().
        add( BOOST_PARAM_TEST_CASE( &free_test_function, params, params+5 ) );

    return 0;
}

//____________________________________________________________________________//

こちらですが、自動でテストケースを認識・実行してくれる AUTO マクロがありません。
そのため、明示的に add する必要があります。

それはちょっと面倒臭い

ということで、簡単にマクロを用意してみました。
#include <boost/test/included/unit_test.hpp>
#include <boost/test/parameterized_test.hpp>
 
#define BOOST_AUTO_TEST_CASE_PARAM( function, begin, end )    \
BOOST_AUTO_TU_REGISTRAR( BOOST_JOIN(registrar, __LINE__)  )(  \
    BOOST_PARAM_TEST_CASE(function, begin, end) )
 
void free_test_function( int i )
{
    BOOST_CHECK( i < 4 /* test assertion */ );
}
 
int params[] = { 1, 2, 3, 4, 5 };
BOOST_AUTO_TEST_CASE_PARAM( &free_test_function, params, params+5 );
(ideone)



テストの中断
Boost.Test では REQUIRE 、Google Test では ASSERT フレーバーが失敗時にテストの中断をします。
ただ、両者でこの中断の挙動が違うので補足をしておきます。

Boost.Test
void SubFunc(void)
{
    BOOST_REQUIRE_EQUAL(0, 1);
    BOOST_REQUIRE_EQUAL(1, 2);
}

BOOST_AUTO_TEST_CASE(Sub)
{
    SubFunc();
    BOOST_REQUIRE_EQUAL(2, 3);
}
Google Test
void SubFunc(void)
{
    ASSERT_EQ(0, 1);
    ASSERT_EQ(1, 2);
}

TEST(Test, Sub)
{
    SubFunc();
    ASSERT_EQ(2, 3);
}
どちらも、アサーションを記述したサブ関数をテストから呼び出しています。
さて、ここで SubFunc(); 後のアサーションに到達するかが、ここでのお話です。
実際の出力を見てみましょう。



Boost.Test
Google Test
ご覧のように、Boost.Test は最初のアサーションの失敗で中断されていますが、Google Test は ASSERT_EQ(2,3); まで到達しています。
これは Google Test の中断が return 文を使った仕組みになっているからです。
なぜこのような実装になっているかは、こちらをご覧ください。

もし、SubFunc 内で失敗したときに、以降の処理を中断したい場合は以下のように書くことができます。
void SubFunc(void)
{
    ASSERT_EQ(0, 1);
    ASSERT_EQ(1, 2);
}

TEST(Test, Sub)
{
    ASSERT_NO_FATAL_FAILURE( SubFunc() );
    ASSERT_EQ(2, 3);
}
ASSERT_NO_FATAL_FAILURE(statement); は、statement で失敗があったかどうかを検証するアサーションです。


このように、SubFunc の失敗によりテストが中断します。

テスト以外での利用
Boost.Test や Google Test などテスティングフレームワークのアサーションは、ログに詳細な情報が出力されるので、普通の assert よりもとても有益な検証になります。
通常、テストの検証として使用するこれらアサーションを、テスト以外の場所でも使おうという話です。

Boost.Test の場合
#define BOOST_TEST_NO_MAIN
#include <boost/test/included/unit_test.hpp>

int main(int , char**)
{
    BOOST_CHECK_EQUAL(2, 3);
    BOOST_REQUIRE_EQUAL(1, 2);
    return 0;
}

特にログも出ずに死亡。うーん、残念。

Google Test の場合
#include <gtest/gtest.h>

void f(void)
{
    ASSERT_EQ(1, 2);
}

int main(int, char**)
{
    EXPECT_EQ(2, 3);
    f();
    return 0;
}


ログが出力されて正常終了しました。
また、GTEST_FLAG マクロを使って失敗時ブレークポイントを有効にすれば、より使い勝手が上がります。
int main(int, char**)
{
    ::testing::GTEST_FLAG(break_on_failure) = true; // break point を有効にする
    EXPECT_EQ(2, 3);
    f();
    return 0;
}

終わり
ちょっとしたことでしたが、補足はこれで終わりです。
また機会があればテスティングフレームワークについて書きたいと思います。

それでは、また来年!

0 件のコメント:

コメントを投稿