Open5

C++テスティングフレームワーク: catch2のメモ

ktz_aliasktz_alias

公式サイト

https://github.com/catchorg/Catch2

インサイドコードテストを書く

  1. catch2/catch_test_macros.hppをインクルードする
  2. TEST_CASE マクロ内にテストを書く
TEST_CASE("テストの概要をここに書く") {
    // ここにテスト内容を書く
}
ktz_aliasktz_alias

提供されているアサーション
See: https://github.com/catchorg/Catch2/blob/devel/docs/assertions.md

  • REQUIRE( expression )
    • expressionfalseの場合に、テストケースをabort
    • ハードアサーション
  • CHECK( expression )
    • expressionfalseの場合に、後続のテストを続行する
    • ソフトアサーション

以下、XXXXにはREQUIRECHECKのいずれかがくる

  • XXXX_FALSE( expression )
    • expressionfalseの場合にテスト失敗にする
  • XXXX_NOTHROW( expression )
    • expressionで例外が送出されたらテスト失敗
    • expressionにはラムダ式の即時実行を記述できる。
      • 以下のTHROW系も同様
  • XXXX_THROWS( expression )
    • expression実行中に例外が送出されることを期待する
  • XXXX_THROWS_AS( expression, exeption )
    • expression実行中にexeptionが送出されることを期待する
  • XXXX_THROWS_WITH( expression, string )
    • expression実行中に例外が送出され、stringに変換される。どうゆうこと?
  • XXXX_THROWS_MATCHES( expression, matcher )
    • expression実行中に例外が送出される場合、matcherで真偽を判定する
    • hamcrestみたいなやつか?
    • 例外用matcherは以下の2つ
      • Message( string )
        • 例外メッセージで判定
      • MessageMatchers( matcher )
        • 文字列系またはventor系matcherを指定して判定
  • XXXX_THAT( lhs, matcher expression )
ktz_aliasktz_alias

matcher

See: https://github.com/catchorg/Catch2/blob/devel/docs/matchers.md#top

複数のmatcherを合成する場合は&&でつなぐ

文字列Matcher

使用する場合は、catch2/matchers/catch_matchers_string.hppをインクルードする
文字列Matcherは名前空間Catch::Matchersに属する

  • StartsWith(std::string str, CaseSensitive)
  • EndsWith(std::string str, CaseSensitive)
  • ContainsSubstring(std::string str, CaseSensitive)
  • Equals(std::string str, CaseSensitive)
  • Matches(std::string str, CaseSensitive)

上4つは命名そのままの意味っぽい
Matchesは正規表現を指定する模様(ECMAScript互換)

Vector系Matcher

  • Contains
    • 指定したvectorが存在するかどうか。多分サブセットっぽい
    • checks whether a specified vector is present in the result
  • VectorContains
    • 指定した1要素が存在するかどうか
    • checks whether a specified element is present in the result
  • Equals
    • 指定したvectorと順序も含め完全一致するかどうか
    • checks whether the result is exactly equal (order matters) to a specific vector
  • UnorderedEquals
    • Equalsの順序不問版
    • checks whether the result is equal to a specific vector under a permutation

その他

  • IsEmpty()
    • std::empty()がtrueとなるかどうかで判定
  • SizeIs(size_t target_size)
    • 範囲のサイズが同じかどうかで判定
  • SizeIs(Matcher size_matcher)
    • 同上
  • Contains(T&& target_element, Comparator = std::equal_to<>{})
    • 範囲内に指定した要素が存在するかどうか
  • Contains(Matcher element_matcher)
    • 同上
  • AllMatch(Matcher element_matcher)
    • コレクション内の全て要素がmatcherを満たすかどうか
  • AnyMatch(Matcher element_matcher)
    • コレクション内のいずれかがmatcherを満たすかどうか
  • NoneMatch(Matcher element_matcher)
    • AllMatchの逆
  • AllTrue()
    • コレクション内の全て要素がtrueかどうか
  • AnyTrue()
    • AllTrueのany版
  • NoneTrue()
    • AllTrueの逆
  • RangeEquals(TargetRangeLike&&, Comparator = std::equal_to<>{})
    • コレクション内の特定範囲のサブセットが順序も含め一致するかどうか・・・ってことかな?
  • UnorderedRangeEquals(TargetRangeLike&&, Comparator = std::equal_to<>{})
    • RangeEqualsの順序不一致版
ktz_aliasktz_alias

#SECTION マクロ

SECTIONは当初、アサーションのラベル付けくらいに考えていた。
が実際はそうではなく、複数のテストセットを作るもの。

例えば

TEST_CASE("test case#1") {
    SECTION("section#1") {
        // (snip)
    }
    SECTION("section#2") {
        // (snip)
    }
}

とした場合、section#1section#2の二つのセクションのテストが構築され実行される。

また以下のように入れ子にした場合、

TEST_CASE("test case#2") {
    SECTION("section group#1") {
        SECTION("section#1") {
            // (snip)
        }
        SECTION("section#2") {
            // (snip)
        }
    }
    SECTION("section group#2") {
        SECTION("section#1") {
            // (snip)
        }
    }
}

section group#1/section#1section group#2/section#1section group#2/section#1のすべてのセクションの組み合わせのテストが構成され実行される。

ここで入れ子のセクションArrange / Actを使う場合は注意が必要。

例えば以下のようにセクションの外でテストハーネスのセットアップする場面を想定する。

TEST_CASE("test case#1") {
    // ここでテストハーネスのセットアップ

    SECTION("section#1") {
        // (snip)
    }
    SECTION("section#2") {
        // (snip)
    }
}

一見、テストハーネスのセットアップが1回だけ行われるように見えるが、実際はセクションごとに実行される。
そのため、アサーションのラベルのつもりで扱うと実行時間がアホほど伸びる羽目になるので要注意。

ちなみに、複数アサーションをブロックで囲みラベル付けする方法は標準では提供されていない模様。