2012年2月18日土曜日

Google Test で Boost.Test の WARN flavor を実現する

Boost.Test には flavors というものがあり、アサーションのレベルがそれぞれ違います。
もちろん、Google Test にも同等のものが存在します。

エラー:ならない
テストの実行:継続
エラー:なる
テストの実行:継続
エラー:なる
テストの実行:中断
Google Test---EXPECTASSERT
Boost.TestWARNCHECKREQUIRE

ご覧のように Google Test には、"エラーにならないアサーション" がありません。
そこで、必要かどうかはさておき Google Test にもエラーにならないアサーションを提供したいと思います。

ベースとなるマクロ
まずは、アサーションで失敗が発生したときに失敗したことにならないようにします。
EXPECT をベースに作っていきましょう。
// GTEST_EXPECT_FAILURE_ をベースに作成
#define GTEST_INFORM_FAILURE_(message) \
 GTEST_MESSAGE_(message, ::testing::TestPartResult::kSuccess)
                                // kSuccess とし成功を指定する

アサーションは最終的に GTEST_<level>_FAILURE_ を呼ぶので、エラーにならないアサーション用に GTEST_INFORM_FAILURE_ を定義します。(エラーにならないアサーションを INFORM としています。)

述語アサーション
次に、ほとんどのアサーションが述語アサーションを利用しているので、そちらを用意します。
#define INFORM_PRED_FORMAT1(pred_format, v1) \
  GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_INFORM_FAILURE_)
#define INFORM_PRED1(pred, v1) \
  GTEST_PRED1_(pred, v1, GTEST_INFORM_FAILURE_)

#define INFORM_PRED_FORMAT2(pred_format, v1, v2) \
  GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_INFORM_FAILURE_)
#define INFORM_PRED2(pred, v1, v2) \
  GTEST_PRED2_(pred, v1, v2, GTEST_INFORM_FAILURE_)
GTEST_INFORM_FAILURE_ を使うように書き換えただけです。
(述語アサーションは "5" まであるので、すべて用意します。)

各アサーションの定義
最後に、INFORM_TRUE とか INFORM_EQ マクロを定義します。
先に定義した述語アサーションを使うようにするだけです。
#define INFORM_TRUE(condition) GTEST_TEST_BOOLEAN_(condition, #condition \
    , false, true, GTEST_INFORM_FAILURE_)

#define INFORM_EQ(expected, actual) \
  INFORM_PRED_FORMAT2(::testing::internal:: \
   EqHelper<GTEST_IS_NULL_LITERAL_(expected)>::Compare, \
   expected, actual)
#define INFORM_NE(expected, actual) \
  INFORM_PRED_FORMAT2(::testing::internal::CmpHelperNE, expected, actual)
#define INFORM_LE(val1, val2) \
  INFORM_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2)
#define INFORM_LT(val1, val2) \
  INFORM_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2)
// 他にもありますが、ここでは省略します。

使い方
他のアサーションと同様に使います。
TEST(InfromTest, Sample)
{
    INFORM_TRUE(rand() != 0);
    INFORM_EQ(5, rand());
}

出力イベントリスナー
さて、ここまで順調にきましたが 問題 が発生します。
Google Test デフォルトの出力イベントリスナーだと何も出力されません。
TestPartResult::kSuccess のときは、何もせず return するようにコーディングされているからです。

そこで、ユーザー定義のイベントリスナーを追加してやります。

class InformPrinter : public ::testing::EmptyTestEventListener
{
private:
 virtual void OnTestPartResult(const TestPartResult& test_part_result)
 {
  // 成功のときに出力
  if( test_part_result.type() == TestPartResult::kSuccess )
  {
   // 出力してもらえるようにダミーのタイプを設定する
   TestPartResult tmp(TestPartResult::kNonFatalFailure
    , test_part_result.file_name()
    , test_part_result.line_number()
    , test_part_result.message());
   ::testing::UnitTest::GetInstance()->
    listeners().default_result_printer()->OnTestPartResult(tmp);
  }
 }
};

int main(int argc, char **argv) {
 testing::InitGoogleTest(&argc, argv);
 // InformPrinter をイベントリスナーに追加
 ::testing::UnitTest::GetInstance()->
  listeners().Append( new InformPrinter() );
 return RUN_ALL_TESTS();
}

iutest でできるようにしました
ここまで紹介してきた INFORM マクロを iutest で使えるようにしました。(v0.18.1.0 以降)
iutest は自作の C++ テストフレームワーク です。
Boost.Test には、include するだけ使える方法もあるようですが、
iutest を使えば、include するだけで Google Test の記法を使うことができます。
詳しくは、 SourceForge.Jp の プロジェクトページ を見てください。

0 件のコメント:

コメントを投稿