C++のユニットテストには Google Test を使ったことがあるが、今は Catch というのが評判いいらしい。 https://t.co/B5eCeGq27Z
— MIURA Masahiro (@Dubhead) 2014, 3月 4というわけで、試した。
チュートリアル
まずは、簡単なサンプルを書きました。Catch は github から clone してきたのを使用しました。Catch はヘッダーのみで使えるので、ライブラリのビルドは不要。パスを通して include するだけで OK です。
#define CATCH_CONFIG_MAIN // main の定義を catch に任せる
#include <catch.hpp>
int f()
{
return 1;
}
TEST_CASE("Test", "[sample]")
{
CHECK( f() == 2 );
REQUIRE( f() <= 0 );
}
実行すると以下のように出力されます。
------------------------------------------------------------------------------- Test ------------------------------------------------------------------------------- main.cpp(9) ............................................................................... main.cpp(11): FAILED: CHECK( f() == 2 ) with expansion: main.cpp(12): FAILED: REQUIRE( f() <= 0 ) with expansion: =============================================================================== 1 test case - failed (2 assertions - both failed)
REQUIRE マクロで式を渡しても、 f() の結果が出力されるのはイイですね!
ドキュメント
さて、ここからはもう少し踏み入って説明したいと思います。と言っても、Catch のドキュメントを見ながらやったことを書き綴るだけですので、公式ドキュメント以上のことはあまり書いてないと思います。その点ご了承くださいm(__)m
アサーションレベル(フレーバー)
まずは、アサーションのレベル(フレーバー)の種類から。| Level | Test Case Fails? | Aborts Execution? |
|---|---|---|
| REQUIRE | Yes | Yes |
| CHECK | Yes | No |
アサーションレベルについては、Boost.Test のそれと似ています。Boost.Test - Assertion Levels
Google Test で言うなら、REQUIRE=ASSERT, CHECK=EXPECT という感じです。
アサーション
続いて、アサーションの種類を紹介します。(REQUIRE を列挙しますが、CHECK もあります。)
| Macro | 概要 | sample |
|---|---|---|
| REQUIRE(expression) | expression が真であることを検証 | REQUIRE( f() == 1 ) |
| REQUIRE_FALSE(expression) | expression が偽であることを検証 | REQUIRE_FALSE( false ) |
| REQUIRE_THROWS(expression) | expression が例外を投げることを検証 | REQUIRE_THROWS(throw 1) |
| REQUIRE_THROWS_AS(expression, type) | expression が例外(type)を投げることを検証 | REQUIRE_THROWS_AS(throw 1, int) |
| REQUIRE_NOTHROW(expression) | expression が例外を投げないを検証 | REQUIRE_NOTHROW(1) |
| REQUIRE_THAT(lhs, matcher call) | lhs が matcher を満たすかを検証 | REQUIRE_THAT("hoge fuga piyo", StartsWith("hoge")) |
必要な機能が全部揃ってる感じですね!すばらしい!
THAT で使える matcher はこちらです。
| name | 概要 |
|---|---|
| AllOf | すべての matcher が真 |
| AnyOf | いづれかの matcher が真 |
| Equals | 文字列の一致 |
| Contains | 文字列の部分一致 |
| StartsWith | 文字列の前方一致 |
| EndsWith | 文字列の後方一致 |
テストケースの作成
テストの入り口となる部分の記述方法です。Catch では、TEST_CASE と SECTION マクロを使って記述します。
TEST_CASE の例:
TEST_CASE("Test", "[sample]")
{
}
TEST_CASE マクロの第一引数はテストの名前です。第二引数にはタグを記述できます。タグについては後述します。TEST_CASE だけでもテストは書けますが、SECTION を使うことで setup/teardown を表現できます。
SECTION を使った例:
TEST_CASE("Test", "[sample]")
{
int a=0;
REQUIRE(a == 0); // 1
puts("1");
SECTION("A")
{
// 2
puts("2");
REQUIRE(a == 0);
++a;
REQUIRE(a == 1);
}
SECTION("B")
{
// 3
puts("3");
REQUIRE(a == 0);
++a;
SECTION("BB")
{
// 4
puts("4");
REQUIRE(a == 1);
}
// 5
puts("5");
REQUIRE(a == 1);
}
SECTION("C")
{
// 6
puts("6");
REQUIRE(a == 1);
}
// 7
puts("7");
puts("---------------");
}
1 7 --------------- 1 2 7 --------------- 1 3 5 7 --------------- 1 3 4 5 7 --------------- 1 6 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ catch_sample.exe is a Catch v1.0 b32 host application. Run with -? for options ------------------------------------------------------------------------------- Test C ------------------------------------------------------------------------------- main.cpp(46) ............................................................................... main.cpp(75): FAILED: REQUIRE( a == 1 ) with expansion: 1 7 --------------- =============================================================================== 1 test case - failed (12 assertions - 1 failed)最後に 1->7 と実行されてるのはバグか?
setup/teardown が同じブロックの中に流れに沿って書けるのため、わかりやすいです。
また、SECTION はネスト可能で、上の場合 Test, Test/A, Test/B, Test/B/BB, Test/C が実行されます。
各セクションは以下の順で実行されます。
| Test | 1 -> 7 |
| Test/A | 1 -> 2 -> 7 |
| Test/B | 1 -> 3 -> 5 -> 7 |
| Test/B/BB | 1 -> 3 -> 4 -> 5 -> 7 |
| Test/C | 1 -> 6 -> 7 |
BDD-style の記述方法もありますが、今回は説明を省きます。
タグ
タグは Google Test にはない概念です。テストにはタグを付けることができます。
TEST_CASE("Test", "[sample]")
タグは1つのテストに複数付けることもできます。
TEST_CASE("Test", "[sample][system][io]")
タグを付けることによって、指定のタグがついたテストだけ実行などができ、テストの分類に役立ちます。
任意のテストのみを実行する方法は次のコマンドライン引数の項で説明します。
コマンドライン引数
| オプション | 値 | 概要 | |
|---|---|---|---|
| [filter ...] | テスト選択フィルター | ||
| --reporter | -r | console xml junit | リポート形式 |
| --break | -b | - | テストが失敗した際に DebugBreak を発生させます |
| --success | -s | - | 成功したテストも表示する |
| --abort | -a | - | REQUIRE レベルの検証に失敗した場合に abort します |
| --abortx | -x | <n> | REQUIRE レベルの検証に n回 失敗した場合に abort します |
| --list-tests | -l | - | テストを列挙します |
| --list-tags | -t | - | タグを列挙します |
| --list-reporters | - | --reporter で使用可能なリポーターを列挙します | |
| --out | -o | <filename> | 出力をファイルに書き出します |
| --name | -n | <name> | テストに名前をつけます(デフォルトは実行ファイル名) |
| --nothrow | -e | - | 例外検証の失敗を無視します e.g. REQUIRE_THROWS |
| --warn | -w | NoAssertions | 警告を表示します |
| --durations | -d | <yes|no> | テスト時間を出力するか指定します |
| --help | -h -? | - | ヘルプ表示 |
実行するテストの選択
テストのフィルタリングはオプション無しで指定します。・ワイルドカードが使用可能
sample.exe Test*・複数指定可能
sample.exe Test2 Test3・タグ指定可能
sample.exe [sample]・除外指定可能
exclude: または ~ を先頭に付けることで除外。
sample.exe exclude:Test2 sample.exe ~Test2 sample.exe ~[sample]・複数タグ指定(AND)
[sample] かつ [test]
sample.exe [sample][test]・複数タグ指定(OR)
[sample] または [test]
sample.exe [sample],[test]
Jenkins で集計
--reporter で junit を選択できるので Jenkins で集計可能です。--reporter junit のみだと標準出力に出力されるので、ファイルに出力する場合はリダイレクトするか --out オプションを使用します。
sample.exe -r junit -o sample.xml
--warn
--warn オプションで指定できるのは現在 NoAssertions のみです。これはセクション内に1つもアサーションが記述されていない場合に警告を出力します。
TEST_CASE("NoTest1", "[no]")
{
}
TEST_CASE("NoTest2", "[sample]")
{
REQUIRE(true);
SECTION("A", "[no]")
{
}
}
------------------------------------------------------------------------------- NoTest1 ------------------------------------------------------------------------------- main.cpp(29) ............................................................................... No assertions in test case 'NoTest1' ------------------------------------------------------------------------------- NoTest2 A ------------------------------------------------------------------------------- main.cpp(33) ............................................................................... No assertions in section 'A'
シャッフルテスト
Google Test や Boost.Test にあるシャッフルテストができないようです。個人的にこれは欲しいので、ちょっと残念です。
まとめ
私は Google Test に慣れているので Catch ではできない機能がある点と、若干記述方法が気になるくらいで、トータル的にCatch イイ感じです。
今回説明を省いた、BDD-style や test-fixture などについては、そのうちまたブログにまとめようと思います。
0 件のコメント:
コメントを投稿