概要
ちょっとしたテストが書きたい、でもちゃんとしたテスティングフレームワークを導入するのは重い…そんな時に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)
EXPR
がEXCEP
型の例外を投げるならテスト成功、EXPR
がEXCEP
型以外の例外を投げる、もしくは例外を投げない場合はテスト失敗となります。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. 続行するには何かキーを押してください . . .