C++と色々

主にC++やプログラムに関する記事を投稿します。

<boost/detail/lightweight_test.hpp>

概要

ちょっとしたテストが書きたい、でもちゃんとしたテスティングフレームワークを導入するのは重い…そんな時にboostのlightweight_testが便利です。
これはboost/detail/lightweight_test.hppにあります。detailディレクトリ以下なのでちょっと分かりにくいですね。
 このフレームワークは最低限のアサーションマクロとレポート関数があるだけで、パラメータ化テストや拡張性などはありません。しかしヘッダをインクルードするだけでOKという手軽さは魅力的で、サンプルコードのテストなどちょっとした時にオススメです!*1

アサーションマクロとレポート関数

lightweight_testで用意されているアサーションマクロを紹介します。全部で5つです。

BOOST_TEST(expr)

exprに真偽値に変換可能な式を書きます。exprが真の時、テストは成功で、儀の時テストは失敗を表します。

BOOST_ERROR(msg)

このマクロを呼び出すとテストが失敗した時と同じような扱いとなり、エラーメッセージmsgを表示します。到達しないはずの文にこのマクロを記述することで正しい文の流れか検証するときなどに使用できます。

BOOST_TEST_EQ(expr1, expr2)

expr1 == expr2が真ならばテスト成功、偽ならばテスト失敗です。式は1度しか評価されませんので、副作用を持っていても1度のみの作用となります。また当然ですが、expr1とexpr2は==で比較可能な型でなければなりません。

BOOST_TEST_NE(expr1, expr2)

expr1 != expr2が真ならばテスト成功、偽ならばテスト失敗です。BOOST_TEST_EQの逆ですね。

BOOST_TEST_THROWS(EXPR, EXCEP)

EXPREXCEP型の例外を投げるならテスト成功、EXPREXCEP型以外の例外を投げる、もしくは例外を投げない場合はテスト失敗となります。EXCEPは例外の型、EXPRは例外を投げるかもしれない(例外を投げると期待する)式文を書きます。セミコロンは要りません。ブロックスコープ{}で囲んであげれば複合文でも大丈夫です。
また、BOOST_NO_EXCEPTIONSマクロを定義するとこのマクロは何も検証しません(EXPRの評価をしません)。

int boost::report_errors()

最後にこの関数を呼び出ます。戻り値はテストが全て成功したならば0を、そうでなければ1を返します。失敗したテスト数などの結果をストリームに書き出します。通常main関数の戻り値にこの関数を呼び出します。

lightweight_testではBOOST_LIGHTWEIGHT_TEST_OSTREAMが定義されており、デフォルトではstd::cerrになっています。このマクロをユーザー定義することで、任意のストリームへの出力へカスタマイズすることが出来ます。

サンプルコード

テストが全て成功する場合

#include <boost/detail/lightweight_test.hpp>
#include <stdexcept>

namespace calc
{
  int add(int l, int r)
  {
    return l + r;
  }

  int sub(int l, int r)
  {
    return l - r;
  }

  int mul(int l, int r)
  {
    return l * r;
  }

  int div(int l, int r)
  {
    if (r == 0) {
      throw std::invalid_argument{""};
    }
    return l / r;
  }
}

int main()
{
  BOOST_TEST_EQ(calc::add(3, 4), 7);
  BOOST_TEST_NE(calc::sub(2, 1), 2);
  BOOST_TEST(calc::mul(7, 8) == 56);
  BOOST_TEST_THROWS(calc::div(3, 0), std::invalid_argument);

  return boost::report_errors();
}

実行結果

No errors detected.
続行するには何かキーを押してください . . .

失敗する場合

#include <boost/detail/lightweight_test.hpp>
#include <stdexcept>

namespace calc
{
  int add(int l, int r)
  {
    return l;
  }

  int sub(int l, int r)
  {
    return l;
  }

  int mul(int l, int r)
  {
    return l;
  }

  int div(int l, int r)
  {
    if (r == 0) {
      return 0;
    }
    return l / r;
  }
}

int main()
{
  BOOST_TEST_EQ(calc::add(3, 4), 7);
  BOOST_TEST_NE(calc::sub(2, 1), 2);
  BOOST_TEST(calc::mul(7, 8) == 56);
  BOOST_TEST_THROWS(calc::div(3, 0), std::invalid_argument);

  return boost::report_errors();
}

実行結果

prog.cpp(32): test 'calc::add(3, 4) == 7' failed in function 'int __cdecl main(v
oid)': '3' != '7'
prog.cpp(33): test 'calc::sub(2, 1) != 2' failed in function 'int __cdecl main(v
oid)': '2' == '2'
prog.cpp(34): test 'calc::mul(7, 8) == 56' failed in function 'int __cdecl main(
void)'
prog.cpp(35): Exception 'std::invalid_argument' not thrown in function 'int __cd
ecl main(void)'
4 errors detected.
続行するには何かキーを押してください . . .

*1:このテスティングフレームワーク自体が約200行程度の1つのファイルのソースコードで出来ているぐらい、軽量です