Skip to content

Instantly share code, notes, and snippets.

@udaken
Last active January 19, 2023 05:39
Show Gist options
  • Save udaken/c375dca1bb6497e48b84d25fc4c77fa4 to your computer and use it in GitHub Desktop.
Save udaken/c375dca1bb6497e48b84d25fc4c77fa4 to your computer and use it in GitHub Desktop.

googletestの高度なトピック

イントロダクション

さて、googletest Primer を読んで、googletest を使ったテストの書き方を学びました。 を読み、googletest を使ってテストを書く方法を学んだので、今度は新しいトリックを学びましょう。このドキュメント このドキュメントでは、より多くのアサーションと、複雑な失敗メッセージの作成方法、致命的な失敗の伝搬について説明します。 メッセージの作成方法、致命的な失敗の伝搬、テストフィクスチャの再利用と高速化、そしてテストでのさまざまなフラグの使用方法です。 様々なフラグをテストに使用する方法を紹介します。

More Assertions

このセクションでは、あまり頻繁に使用されないが、それでも重要なものを取り上げます。 アサーションについて説明します。

成功・失敗の明示

アサーションリファレンスの明示的な成功と失敗を参照してください。 を参照してください。

例外のアサーション

アサーション](reference/assertions.md#exceptions)を参照してください。 を参照してください。

エラーメッセージを改善する述語アサーション

googletest には豊富なアサーションがありますが、完全なアサーションであることはありません。 ユーザーが遭遇する可能性のあるすべてのシナリオを予想することは不可能です (良い考えでもありません)。 というのも、ユーザーが遭遇する可能性のあるすべてのシナリオを予想することは不可能だからです。そのため、時には EXPECT_TRUE() を使って複雑な式をチェックしなければならないこともあります。 より良いマクロがないため、ユーザは EXPECT_TRUE() を使って複雑な式をチェックしなければならないことがあります。これには、以下のような問題があります。 これは、式の部分の値を表示しないので、何が問題だったのかを理解するのが難しいという問題があります。 何が問題だったのかを理解するのが難しくなります。回避策として、ユーザーによっては、失敗メッセージを自分で作成し EXPECT_TRUE()` にストリーミングして、失敗メッセージを自分で作成します。しかし、これは は厄介です。特に、式に副作用があったり、評価にコストがかかったりする場合には。 を評価するのが面倒です。

googletestでは、この問題を解決するために3種類の選択肢が用意されています。

既存のブール関数を使用する場合

もし、既に bool を返す関数やファンクタ(あるいは bool に暗黙的に変換できる型)を持っているならば、それを predicate に使うことができます。 を返す関数やファンクタ(あるいは暗黙のうちに bool に変換できる型)がある場合、それを 述語 で使用することができます。 アサーション で使用することができます。参照 アサーションリファレンスの [EXPECT_PRED*] (reference/assertions.md#EXPECT_PRED) を参照してください。 リファレンスを参照してください。

AssertionResultを返す関数を使用する

EXPECT_PRED*() とその仲間は素早く仕事をするのに便利ですが、構文は満足のいくものではありません。 アリティごとに異なるマクロを使わなければならず、C++というよりLispのような感じです。 C++というよりLispのような感じです。testing::AssertionResult` クラスはこの問題を解決してくれます。 クラスがこの問題を解決してくれます。

AssertionResult オブジェクトは、アサーションの結果 (成功か失敗か、そして関連するメッセージ) を表します。 と関連するメッセージ) を表します。オブジェクトを作成することができます。 AssertionResult` を作成するには、これらのファクトリ関数のいずれかを使用します。

namespace testing {

// AssertionResult オブジェクトを返し、アサーションが成功したことを示す。
// オブジェクトを返す。
AssertionResult AssertionSuccess();

// AssertionResult オブジェクトを返し、アサーションが失敗したことを示す。
// 失敗したことを示す AssertionResult オブジェクトを返します。
AssertionResult AssertionFailure();

}

次に、<< 演算子を使用して、メッセージを AssertionResult にストリームすることができます。 オブジェクトにメッセージを流すことができます。

ブール型アサーション (例: EXPECT_TRUE()) において、より読みやすいメッセージを提供するためです。 の代わりに AssertionResult を返す述語関数を書きます。例えば 例えば、 IsEven() を次のように定義するとします。

testing::AssertionResult IsEven(int n) {
  if ((n % 2) == 0)
    return testing::AssertionSuccess();
  else
    return testing::AssertionFailure() << n << " is odd";
}

の代わりに

bool IsEven(int n) {
  return (n % 2) == 0;
}

という失敗したアサーションが表示されます。

Value of: IsEven(Fib(4))
  Actual: false (3 is odd)
Expected: true

の代わりに、より不透明な

Value of: IsEven(Fib(4))
  Actual: false
Expected: true

EXPECT_FALSEASSERT_FALSE にも情報を表示させたい場合は、次のようにします。 (Google コードベースのブール型アサーションの 3 分の 1 は否定的なものです)、そして 成功した場合に述語が遅くなることに抵抗がなければ 成功のメッセージを与えることができます。

testing::AssertionResult IsEven(int n) {
  if ((n % 2) == 0)
    return testing::AssertionSuccess() << n << " is even";
  else
    return testing::AssertionFailure() << n << " is odd";
}

すると、EXPECT_FALSE(IsEven(Fib(6)))という文が表示されます。

  Value of: IsEven(Fib(6))
     Actual: true (8 is even)
  Expected: false

述語フォーマッタの使用方法

によって生成されたデフォルトのメッセージを見つけた場合、そのメッセージは EXPECT_PRED*] (reference/assertions.md#EXPECT_PRED) と [EXPECT_TRUE によって生成されるデフォルトのメッセージが満足のいくものでない場合、あるいは、述語のいくつかの引数が 述語の引数が ostream へのストリーミングをサポートしていない場合、代わりに *predicate-format を使用することができます。 代わりに predicate-formatter アサーション を使って、メッセージがどのようにフォーマットされるかを fully カスタマイズすることができます。 メッセージのフォーマットをカスタマイズすることができます。以下を参照してください。 の [EXPECT_PRED_FORMAT*] (reference/assertions.md#EXPECT_PRED_FORMAT) を参照してください。 アサーションリファレンス を参照してください。

浮動小数点演算の比較

浮動小数点演算の比較を参照してください。 Assertions Reference を参照してください。

浮動小数点述語フォーマット関数

浮動小数点演算は便利なものもありますが、それほど頻繁に使うものではありません。そのため 新しいマクロが爆発的に増えるのを避けるため、述語形式関数として提供する。 として提供し、述語アサーションマクロで使用することができます。 [EXPECT_PRED_FORMAT2] (reference/assertions.md#EXPECT_PRED_FORMAT) のように、述語フォーマット関数として提供します。 例えば

using ::testing::FloatLE;
using ::testing::DoubleLE;
...
EXPECT_PRED_FORMAT2(FloatLE, val1, val2);
EXPECT_PRED_FORMAT2(DoubleLE, val1, val2);

上のコードは val1val2 よりも小さいか、ほぼ等しいことを検証しています。 と等しいことを検証します。

gMock Matcherを使ったアサーション

アサーションリファレンスの EXPECT_THAT を参照してください。 を参照してください。

その他の文字列アサーション

(まだの方は のセクションを先にお読みください。 を読んでください)。

gMock の string matchers を利用することができます。 と EXPECT_THAT を使って、さらに多くの文字列比較のトリックを行うことができます。 (reference/assertions.md#EXPECT_THAT`) を使って、より多くの文字列比較のトリック(サブストリング、プレフィックス、サフィックス、正規表現、その他)を行うことができます。例えば の例です。

using ::testing::HasSubstr;
using ::testing::MatchesRegex;
...
  ASSERT_THAT(foo_string, HasSubstr("needle"));
  EXPECT_THAT(bar_string, MatchesRegex("\\w*\\d+"));

Windows HRESULT アサーション

アサーションリファレンスのWindows HRESULTアサーションを参照してください。 アサーションリファレンス]を参照してください。

タイプアサーション

関数を呼び出すことができます。

::testing::StaticAssertTypeEq<T1, T2>();

を呼び出して、型 T1T2 が同じであることを表明します。この関数は、もし を返します。型が異なる場合、この関数の呼び出しはコンパイルに失敗します。 コンパイラのエラーメッセージは、 T1 と T2 は同じ型ではない と表示されます。 というエラーメッセージが表示され、(コンパイラによっては)実際の T1T2` の実際の値が表示されます。これは主にテンプレートコードの中で役に立ちます。

注意:クラステンプレートや関数テンプレートのメンバ関数内で使用された場合、 StaticAssertTypeEq<T1, T2>() のメンバ関数内で使われた場合, StaticAssertTypeEq<T1, T2>()` は,その関数がインスタンス化されたときのみ有効です。 がインスタンス化されている場合のみ有効です。例えば、与えられた

template <typename T> class Foo {
 public:
  void Bar() { testing::StaticAssertTypeEq<int, T>(); }
};

を表示します。

void Test1() { Foo<bool> foo; }

はコンパイラエラーを発生させません。 は実際にはインスタンス化されないからです。その代わり、必要なのは

void Test2() { Foo<bool> foo; foo.Bar(); }

を使用すると、コンパイラーエラーが発生します。

アサーション配置

C++の関数であれば、どのようなものでもアサーションを使用することができます。特に、テストフィクスチャクラスのメソッドである必要はありません。 メソッドである必要はありません。1 つの制約として、致命的な失敗を生成するアサーション (FAIL*ASSERT_*) は 致命的な失敗を生成するアサーション (FAIL*ASSERT_*) は、以下の関数の中でしか使用できません。 を返す関数にしか使えないということです。これは、Google が例外を使用しないことに起因しています。 の例外を使用しないことの結果です。これを void でない関数の中に置くと、コンパイル時に `"error: void value" という紛らわしいエラーが発生します。 のようなコンパイルエラーが発生します。

"error: void value not ignored as it ought to be" or "cannot initialize return object of type 'bool' with an rvalue of type 'void'" or "error: no viable conversion from 'void' to 'string'".

非voidを返す関数で致命的なアサーションを使用する必要がある場合、1つのオプションは、関数が代わりにoutパラメータで値を返すようにすることです。 を返す関数で致命的なアサーションを使う必要がある場合は、 代わりにその関数を out パラメータで返すようにするのもひとつの方法です。たとえば を void Foo(T1 x, T2* result) に書き換えることができます。このとき 関数が早期に戻った場合でも、 *result に何らかの適切な値が含まれていることを確認する必要があります。 を確実に含むようにする必要があります。この関数は void を返すようになったので、その内部で任意のアサーションを使用することができます。 を返すようになったので、その内部で任意のアサーションを使用することができます。

もし関数の型を変更することができないのなら、 ADD_FAILURE*EXPECT_* のような致命的ではない失敗を生成するアサーションを使うべきでしょう。 のような致命的でない失敗を発生させるアサーションを使用する必要があります。

{: .callout .note} 注:コンストラクタとデストラクタは void-return関数とみなされません。 C++言語仕様によると、コンストラクタとデストラクタはvoid return関数とはみなされません。 アサーションを使用してはいけません。その代わり、以下のどちらかを行ってください。 を呼び出してテスト実行ファイル全体をクラッシュさせるか、あるいは致命的なアサーションを に入れるか、あるいは SetUp/TearDown 関数に致命的なアサーションを入れてください。 [コンストラクタ/デストラクタ vs. SetUp/TearDown] (faq.md#CtorVsSetUp) を参照してください。

{: .callout .warning} 警告: ヘルパー関数 (プライベート void リターンメソッド) の致命的なアサーションは、コンストラクタまたはデストラクタから呼び出されます。 の致命的なアサーションは、直感的にわかるように現在のテストを終了させるものではありません。 単にコンストラクタやデストラクタを早期に終了させるだけです。 コンストラクタやデストラクタから呼び出されたヘルパー関数(private void return method)は、 直感的には現在のテストを終了させるものではありません。 を残してしまうかもしれません。ほぼ間違いなく abort するか、あるいは SetUp/TearDown` を代わりに使用することになるでしょう。

テスト実行をスキップする

SUCCEED()FAIL() のアサーションに関連して、 GTEST_SKIP() マクロを使うと、それ以上テストが実行されないようにすることができます。 マクロを使うことで、実行時にそれ以上のテストが実行されないようにすることができます。これは、以下のような場合に便利です。 これは、実行中にテスト対象のシステムの前提条件をチェックし、意味のある形でテストをスキップする必要がある場合に便利です。 をスキップしたい場合に便利です。

GTEST_SKIP()は、個々のテストケースやSetUp()` メソッドの中で使用することができます。 のメソッドで使用することができます。 例えば

TEST(SkipTest, DoesSkip) {
  GTEST_SKIP() << "シングルテストをスキップする";
  EXPECT_EQ(0, 1); // 失敗しない、実行されない
}

class SkipFixture : public ::testing::Test {
 protected:
  void SetUp() override {
    GTEST_SKIP() << "このフィクスチャのすべてのテストをスキップする";
  }
};

// SkipFixture のテストは実行されません。
TEST_F(SkipFixture, SkipsOneTest) {
  EXPECT_EQ(5, 7); // 失敗しない。
}

アサーションマクロと同様に、GTEST_SKIP() にカスタムメッセージを流し込むことができます。

Teaching googletest How to Print Your Values

EXPECT_EQ` のようなテストアサーションが失敗すると、 googletest は引数の値を表示します。 の値を表示してデバッグを支援します。これは、ユーザーが拡張できる値プリンターを用いて行います。

このプリンタは、C++の組み込み型、ネイティブ配列、STL コンテナ、および << 演算子をサポートする任意の型を印刷する方法を知っています。その他の型については その他の型については、値の中の生のバイトを印刷し、ユーザがそれを理解することを望みます。

前述したように、このプリンターは拡張可能です。つまり、バイトをダンプするよりも バイトをダンプするよりも、あなたの特定のタイプをプリントする方が良い仕事をするように、それを教えることができるということです。そのためには を定義してください。

#include <ostream>

namespace foo {

class Bar { // googletestがこのインスタンスを表示できるようにしたい。
...
  // フリーのインラインフレンド関数を作成します。
  friend std::ostream& operator<<(std::ostream& os, const Bar& bar) {
    return os << bar.DebugString(); // bar を os に出力するために必要なもの。
    }
};

// クラス内で関数を宣言できない場合、重要なことは
<< 演算子は、Bar を定義しているネームスペースで定義されていることが重要です。  C++ のルックアップ
// ルックアップのルールに依存します。
std::ostream& operator<<(std::ostream& os, const Bar& bar) {
  return os << bar.DebugString(); // bar を os に出力するために必要なもの。
}

}  // namespace foo

時には、これはオプションではありません。 を使うのはスタイルが悪いと考えるかもしれませんし、 Bar にはすでに << 演算子が存在していて、それを変更することができないかもしれません。 演算子を持っていて、それを変更することはできません。もしそうなら、代わりに のような PrintTo() 関数を定義します。

#include <ostream>

namespace foo {

class Bar {
  ...
  friend void PrintTo(const Bar& bar, std::ostream* os) {
    *os << bar.DebugString(); // bar を os に出力するために必要なものすべて
  }
};

// クラス内で関数を宣言できない場合、PrintTo() が Bar を定義する SAME ネームスペースで定義されていることが重要です。
// は、Bar を定義しているネームスペースで定義されていることが重要です。  C++のルックアップ・ルールはこれに依存しています。
// C++ のルックアップ・ルールはこれに依存しています。
void PrintTo(const Bar& bar, std::ostream* os) {
  *os << bar.DebugString(); // bar を os に出力するために必要なものすべて
}

}  // namespace foo

もし <<PrintTo() の両方を定義していた場合は、後者を使用します。 が使われます。これにより、その動作に依存するコードに影響を与えることなく の動作に依存するコードに影響を与えることなく、googletest の出力に表示される値をカスタマイズすることができます。 演算子の挙動に依存するコードに影響を与えることなく、googletest の出力に表示される値をカスタマイズすることができます。

もし、googletest の値プリンタを使って、値 x を自分で印刷したい場合は を呼び出すと、 std::string が返されます。

vector<pair<Bar, int> > bar_ints = GetBarIntVector();

EXPECT_TRUE(IsCorrectBarIntVector(bar_ints))
    << "bar_ints = " << testing::PrintToString(bar_ints);

デス・テスト

多くのアプリケーションでは、以下の条件を満たさない場合、アプリケーションの失敗を引き起こす可能性のあるアサーションが存在します。 多くのアプリケーションには、条件が満たされないとアプリケーションを失敗させるアサーションがある。これらの一貫性チェックは、プログラムが既知の良い状態にあることを保証するものです。 このような一貫性チェックは、プログラムが既知の良好な状態にあることを保証するもので、あるプログラム状態が破壊された後、可能な限り早い時期に失敗するように用意されています。 プログラムの状態が破壊された後、可能な限り早い段階で失敗するようになっています。もしアサーションが間違った条件をチェックした場合、プログラムはエラーになる可能性があります。 プログラムが誤った状態で進行し、メモリの破壊やセキュリティホールの発生、あるいはさらに悪い事態を引き起こす可能性があります。 その結果、メモリの破壊やセキュリティホールが発生したり、最悪の事態に陥る可能性があります。したがって、このようなアサーション文が期待通りに動作するかどうかをテストすることは、極めて重要です。 このようなアサーション文が期待通りに動作することをテストすることは非常に重要です。

このような前提条件のチェックはプロセスを死なせてしまうので、このようなテストを デステストと呼ぶことにします。より一般的には、プログラムが期待されたとおりに終了するかどうかをチェックするテストも (例外の発生を除く) が期待通りに終了することを確認するテストもまた、デステストとなります。

コードの一部が例外を投げても、それを「死」と見なさないことに注意してください。 というのも、そのコードの呼び出し元はその例外をキャッチし、クラッシュを回避することができるからです。 例外をキャッチしてクラッシュを回避できるからです。もし、自分のコードが投げる例外を検証したいのであれば を検証したい場合は、 Exception Assertions を参照してください。

テストコードで EXPECT_*()/ASSERT_*() の失敗をテストしたい場合、以下を参照してください。 失敗をキャッチする を参照してください。

デス テストの書き方

GoogleTest はデステストをサポートするアサーションマクロを提供しています。以下を参照ください。 アサーションリファレンス の Death Assertions を参照ください。 を参照ください。

デステストを書くには、テスト関数の中でマクロの一つを使うだけです。 たとえば

TEST(MyDeathTest, Foo) {
  // この死亡テストは複合ステートメントを使用します。
  ASSERT_DEATH({
    int n = 5;
    Foo(&n);
  }, "Error on line .* of Foo()");
}

TEST(MyDeathTest, NormalExit) {
  EXPECT_EXIT(NormalExit(), testing::ExitedWithCode(0), "Success");
}

TEST(MyDeathTest, KillProcess) {
  EXPECT_EXIT(KillProcess(), testing::KilledBySignal(SIGKILL),
              "Sending myself unblockable signal");
}

が検証します。

  • Foo(5)` を呼び出すと、与えられたエラーメッセージとともにプロセスが終了します。
  • NormalExit()を呼び出すと、プロセスは "Success"` を標準エラー出力に出力し、終了コード 0 で終了します。 終了コード 0 で終了します。
  • KillProcess()を呼び出すと、シグナルSIGKILL` でプロセスを終了します。

テスト関数本体には、必要に応じて他のアサーションやステートメントを含めることができます。 必要であれば

デステストは、3つのことしか気にしないことに注意してください。

  1. statement はプロセスを中断または終了させるか?
  2. (ASSERT_EXITEXPECT_EXIT の場合) 終了ステータスは predicate を満たすか? は predicate を満たすか?または (ASSERT_DEATHEXPECT_DEATH の場合) 終了ステータスが 0 以外か? は、終了ステータスが 0 以外であるか?そして
  3. 標準エラー出力は matcher と一致するか?

特に、 statementASSERT_*EXPECT_* の失敗を生成した場合、そのテストは失敗します。 はデステストを失敗させることはありません。 が失敗することはありません。

デステスネーミング

{: .callout .important} 重要: 私たちは、以下の命名規則に従うことを強く推奨します。 テストスイート (テストではありません) の名前を *DeathTest とすることを強く推奨します。 という名前をつけることを強く推奨します。その Death Tests And Threads のセクションで、その理由を説明しています。

テストフィクスチャのクラスが通常のテストとデステストで共有される場合、 usingtypedef を使うことができます。 を使うことで、フィクスチャクラスのエイリアスを作成し、コードの重複を避けることができます。 そのコードの重複を避けることができます。

class FooTest : public testing::Test { ... };

using FooDeathTest = FooTest;

TEST_F(FooTest, DoesThis) {
  // 通常のテスト
}

TEST_F(FooDeathTest, DoesThat) {
  // デステスト
}

正規表現の構文

Bazel でビルドして Abseil を使う場合、googletest では RE2 構文を使用します。それ以外の場合、POSIX システム (Linux, Cygwin, Mac) の場合、googletest は次の構文を使います。 POSIX 拡張正規表現 を使用します。 の構文を使用します。POSIX 構文について学ぶには、次のものを読むとよいでしょう。 Wikipedia の項目 を参照してください。

Windowsでは、googletestは独自の単純な正規表現の実装を使用します。これは は多くの機能を欠いています。例えば、和集合 ("x|y"), グループ化 ("(xy")) はサポートしていません。 ("(xy)"), 括弧 ("[xy]"), 繰り返し回数 ("x{5,7}") などはサポートしていません。 などがあります。以下は、私たちがサポートしているものです(Aは、リテラル文字、ピリオド (.), または単一の Щ エスケープシーケンス; xy は正規表現を表します。 式を表す)。

Expression Meaning
c matches any literal character c
\\d matches any decimal digit
\\D matches any character that's not a decimal digit
\\f matches \f
\\n matches \n
\\r matches \r
\\s matches any ASCII whitespace, including \n
\\S matches any character that's not a whitespace
\\t matches \t
\\v matches \v
\\w matches any letter, _, or decimal digit
\\W matches any character that \\w doesn't match
\\c matches any literal character c, which must be a punctuation
. matches any single character except \n
A? matches 0 or 1 occurrences of A
A* matches 0 or many occurrences of A
A+ matches 1 or many occurrences of A
^ matches the beginning of a string (not that of each line)
$ matches the end of a string (not that of each line)
xy matches x followed by y

あなたのシステムでどの機能が利用できるかを判断するために、googletest はどの正規表現を使うかを決めるためにマクロを定義しています。マクロは以下の通りです。 GTEST_USES_SIMPLE_RE=1またはGTEST_USES_POSIX_RE=1` です。もし、あなたのデス を使うか、より限定的な構文のみを使うことができます。 限定的な構文のみを使用します。

仕組み

アサーションの 死のアサーション を参照してください。 を参照してください。

デステスとスレッド

2つのデステストスタイルを採用した理由は、スレッドの安全性に関係しています。なぜなら スレッドが存在する場合のフォークの問題はよく知られているので、デステストはシングルスレッドで実行されるべきです。 はシングルスレッドのコンテキストで実行されるべきです。しかし、時にはそのような環境を整えることが不可能な場合もあります。 しかし、そのような環境を整えることができない場合もあります。たとえば、静的に初期化されたモジュール は main に到達する前にスレッドを開始することがあります。一旦スレッドが生成されると 一旦スレッドが生成されると、それをクリーンアップするのは難しいか不可能です。

googletestには、スレッドの問題に対する意識を高めることを目的とした3つの機能があります。

  1. 複数のスレッドが実行されている場合、デステストに遭遇したときに警告が発せられます。 警告が発せられる。
  2. DeathTest" で終わる名前のテスト・スイートは、他のすべてのテストの前に実行されます。 実行されます。
    1. Linux では、子プロセスの生成に fork() の代わりに clone() を使用します。 (CygwinとMacでは clone() は利用できません) 。 は、親プロセスが複数のスレッドを持つ場合に、子プロセスがハングする可能性が高いからです。

デステスト文の中にスレッドを作成するのは全く問題ありません。 それらは別のプロセスで実行され、親プロセスに影響を与えることはできません。

デステラスタイル

スレッドセーフ "デステストスタイルは、マルチスレッド環境でのテストのリスクを軽減するために導入されました。 マルチスレッド環境でのテストのリスクを軽減するために導入されました。これは、テスト実行時間の増加(劇的に増加する可能性があります)と、スレッドセーフの向上をトレードするものです。 テスト実行時間の増加(劇的に増加する可能性があります)と、スレッドセーフの改善をトレードします。

自動テストフレームワークでは、スタイルフラグは設定されません。プログラム上でフラグを設定することで フラグを設定することで、特定のスタイルのデステストを選ぶことができます。

GTEST_FLAG_SET(death_test_style, "threadsafe")

バイナリ内のすべてのテストのスタイルを設定するには、 main() の中でこれを行います。 あるいは個々のテストに対して行うことができます。フラグは各テストを実行する前に保存され、実行後に復元されることを思い出してください。 そのため、自分でそれを行う必要はありません。例えば

int main(int argc, char** argv) { { テスト::InitGoogleTest(&argc, argv)
  testing::InitGoogleTest(&argc, argv);
  GTEST_FLAG_SET(death_test_style, "fast");
  return RUN_ALL_TESTS();
}

TEST(MyDeathTest, TestOne) {
  GTEST_FLAG_SET(death_test_style, "threadsafe");
  // このテストは "スレッドセーフ" スタイルで実行されます。
  ASSERT_DEATH(ThisShouldDie(), "");
}

TEST(MyDeathTest, TestTwo) {
  // このテストは "fast" スタイルで実行されます。
  ASSERT_DEATH(ThisShouldDie(), "");
}

注意事項

ASSERT_EXIT()statement 引数は、任意の有効な C++ 文とすることができます。もし が return 文を介して、あるいは例外を投げることによって現在の関数から抜ける場合、デステストは失敗したとみなされます。 を投げると、デステストは失敗したとみなされます。googletest のマクロの中には は現在の関数から戻ることがあります (例えば ASSERT_TRUE()) ので、 statement の中では避けるようにしてください。 を避けるようにしてください。

statementは子プロセスで実行されるので、メモリ内の副作用(例えば、変数の変更、メモリの解放など)が発生しても が発生しても、親プロセスでは観測されません。 は親プロセスでは観測されません。特に、デステストでメモリを解放した場合。 特に、デステストでメモリを解放した場合、ヒープチェックに失敗します。 を見ることができないからです。この問題を解決するには、次のようにします。

1.死亡診断でメモリを解放しないようにする。 2. 親プロセスで再びメモリを解放する。 3. プログラムでヒープチェッカーを使用しない。

実装の詳細のため、複数のデステストアサーションを同じ行に配置することはできません。 を同じ行に記述することはできません。 メッセージを表示します。

スレッドセーフ "スタイルによってスレッドセーフが向上したにもかかわらず、デス テストによってスレッドセーフになったとはいえ、デッドロックのようなスレッド問題は で登録されたハンドラが存在する場合、デッドロックのようなスレッド問題が発生する可能性があります。

サブルーチンでアサーションを使用する

{: .callout .note} 注意: 一連のテスト・アサーションをサブルーチンの中に入れて、 複雑な条件をチェックしたい場合は、次のようにします。 を使いたい場合は カスタム GMock matcher を使うことを検討してください。こうすることで これにより、失敗した場合にもっと読みやすいエラーメッセージを提供することができ、 また、以下に説明するすべての問題を避けることができます。 の問題を回避できます。

アサーションにトレースを追加する

あるテストサブルーチンが複数の場所から呼び出された場合、その中のアサーションが失敗すると、どのサブルーチンの呼び出しが失敗だったのかがわからなくなります。 が失敗したときに、その失敗がどのサブルーチンのものなのかを判断するのが難しい場合があります。 を見分けるのは困難です。この問題を解決するには、特別なロギングや独自の失敗メッセージを使用します。 を使用することで、この問題を回避することができます。よりよい解決策は SCOPED_TRACEマクロかScopedTrace` ユーティリティを使うことです。

SCOPED_TRACE(message);
ScopedTrace trace("file_path", line_number, message);

ここで、 message には std::ostream にストリームできるものなら何でも指定できる。SCOPED_TRACE マクロは、失敗したときのメッセージに、現在のファイル名、行番号、そして指定されたメッセージを追加します。 マクロは、すべての失敗メッセージに現在のファイル名、行番号、与えられたメッセージを追加します。ScopedTrace は明示的なファイル名と行番号を引数として受け取ることができます。 これはテストヘルパーを書くときに便利です。この効果は は、コントロールが現在のレキシカルスコープから離れると、元に戻ります。

例えば、こんな感じです。

10: void Sub1(int n) {
11: EXPECT_EQ(Bar(n), 1);
12: EXPECT_EQ(Bar(n + 1), 2);
13: }
14:
15: TEST(FooTest, Bar) {
16: {
17: SCOPED_TRACE("A"); // このトレースポイントは、このスコープでの全ての失敗に含まれます。
18: // このスコープでの全ての失敗に含まれます。
19: Sub1(1);
20: }
21: // 今度はそうならない。
22: Sub1(9);
23: }

のようなメッセージが表示されることがありました。

path/to/foo_test.cc:11: Failure
Value of: Bar(n)
Expected: 1
  Actual: 2
Google Test trace:
path/to/foo_test.cc:17: A

path/to/foo_test.cc:12: Failure
Value of: Bar(n + 1)
Expected: 2
  Actual: 3

トレースがなければ、2つの失敗がそれぞれどの Sub1() のどちらの呼び出しで失敗したのかを知るのは難しいでしょう。(あなたは、Sub1()の各アサーションに、Sub1()の値を示す Sub1() の各アサーションに、 n の値を示すメッセージを追加することもできますが、それは面倒です。 を示すメッセージを追加することもできますが、面倒です)。

SCOPED_TRACE` を使用する際のいくつかのヒントを紹介します。

  1. 適切なメッセージがあれば、各コールサイトではなく、サブルーチンの最初に SCOPED_TRACE を使用することで十分な場合があります。
  2. ループ内のサブルーチンを呼び出すときは、SCOPED_TRACEのメッセージにループのイテレータを含ませて、失敗がどのイテレータからのものかを分かるようにします。 を知ることができるようにします。
  3. トレースポイントの行番号で、サブルーチンの特定の呼び出しを特定できることがあります。この場合、SCOPED_TRACE のためのユニークなメッセージを選ぶ必要はありません。 SCOPED_TRACE のためにユニークなメッセージを選択する必要はありません。単に "" を使用することができます。
  4. 外側のスコープにトレースポイントがある場合、内側のスコープで SCOPED_TRACE を使用できます。この場合、すべてのアクティブなトレースポイントは、失敗のメッセージに含まれます。 この場合、すべてのアクティブなトレースポイントは、それらが遭遇した逆順で、失敗メッセージに含まれます。
  5. トレースダンプはEmacsでクリックすることができます。 行番号の上で return を押すと、ソースファイルのその行に移動します!

致命的な故障の伝搬

ASSERT_FAIL` を使用する際によくある落とし穴は、それらが失敗したときに、テスト全体ではなく _current の関数を中断するだけだということを理解していないことです。 が失敗したとき、テスト全体ではなく _current の関数だけを中断させるということを理解していないことです。例えば 例えば、次のようなテストはセグメンテーションに失敗します。

void Subroutine() {
  // 致命的な失敗を発生させ、現在の関数を中止する。
  ASSERT_EQ(1, 2);

  // 以下は実行されません。
  ...
}

TEST(FooTest, Bar) {
  Subroutine(); // 想定される動作は、Subroutine() の致命的な失敗によってテスト全体が中断されることです。
                 // サブルーチン() の中で致命的な失敗をすると、テスト全体が中断されます。

  // 実際の動作:サブルーチン()が戻った後、この関数は続行します。
  int* p = nullptr;
  *p = 3; // セグメンテーション違反!
}

これを軽減するために、googletestは3つの異なる解決策を提供しています。使用できるのは 例外、 (ASSERT|EXPECT)_NO_FATAL_FAILURE アサーション、そして HasFatalFailure()` 関数です。これらは次の2つのサブセクションで説明します。 サブセクションで説明します。

例外を発生させたサブルーチンに対するアサーション

以下のコードで、ASSERT-failureを例外にすることができます。

class ThrowListener : public testing::EmptyTestEventListener {
  void OnTestPartResult(const testing::TestPartResult& result) override {
    if (result.type() == testing::TestPartResult::kFatalFailure) {
      throw testing::AssertionException(result);
    }
  }
};
int main(int argc, char** argv) {
  ...
  testing::UnitTest::GetInstance()->listeners().Append(new ThrowListener);
  return RUN_ALL_TESTS();
}

このリスナーは、他のリスナーが存在する場合はその後ろに追加する必要があります。 リスナーは失敗した OnTestPartResult を見ることができません。

サブルーチンのアサーション

上に示したように、もしテストが ASSERT_* という失敗を含むサブルーチンを呼び出した場合、そのサブルーチンが戻った後もテストは継続されます。 を持つサブルーチンを呼び出すと、そのサブルーチンが戻った後もテストは続行されます。これは を実行します。

しばしば、致命的な失敗を例外のように伝播させたいと考える人がいます。そのために googletest は以下のマクロを提供します。

致命的なアサーション 非致命的なアサーション ベリファイ
ASSERT_NO_FATAL_FAILURE(statement); EXPECT_NO_FATAL_FAILURE(statement); statement は現在のスレッドで新しい致命的な失敗を生成しないことを確認します。

アサーションを実行したスレッドでの失敗のみがチェックされ、このタイプのアサーションの結果を決定します。 このタイプのアサーションの結果を決定するためにチェックされます。もし statement が新しいスレッドを作成したら、そのスレッドでの失敗は無視されます。 の失敗は無視されます。

ASSERT_NO_FATAL_FAILURE(Foo());

int i;
expect_no_fatal_failure({)
  i = Bar();
});

複数のスレッドからのアサーションは、現在Windowsではサポートされていません。

現在のテストに失敗していないか確認する

クラス ::testing::TestHasFatalFailure() は、現在のテストに含まれるアサーションが致命的な失敗をした場合に true を返します。 を返します。これによって 関数がサブルーチン内で致命的な失敗をキャッチし、早期にリターンすることができます。

class Test {
 public:
  ...
  static bool HasFatalFailure();
};

典型的な使い方で、基本的にはスローされた例外の挙動をシミュレートしています。 です。

TEST(FooTest, Bar) {
  Subroutine();
  // サブルーチン()が致命的な失敗をした場合は中止する。
  if (HasFatalFailure()) return;

  // 以下は実行されません。
  ...
}

もし HasFatalFailure()TEST() , TEST_F() , またはテストフィクスチャの外で使われるなら、以下のように ::testing::test:: という接頭辞を付けなければなりません。 フィクスチャの外部で使用する場合は、以下のように ::testing::Test:: というプレフィックスを付けなければなりません。

if (testing::Test::HasFatalFailure()) return;

同様に、HasNonfatalFailure() は現在のテストに致命的でない失敗が少なくとも1つあれば true を返します。 を返し、 HasFailure() は現在のテストに少なくとも 1 つの致命的でない失敗があれば true を返します。 は true を返し、HasFailure() は現在のテストに少なくとも1つの失敗があれば、そのどちらかを返します。

ログの追加情報

テストコードでは、 RecordProperty("key", value) を呼び出して追加の情報を記録することができます。 ここで、 value は文字列か int のどちらかです。キーに記録された 最後の 値 に出力されます。 XML出力が指定されていれば、その値になります。例えば テスト

TEST_F(WidgetUsageTest, MinAndMaxWidgets) {
  RecordProperty("MaximumWidgets", ComputeMaxUsage());
  RecordProperty("MinimumWidgets", ComputeMinUsage());
}

は、次のようなXMLを出力します。

  ...
    <testcase name="MinAndMaxWidgets" file="test.cpp" line="1" status="run" time="0.006" classname="WidgetUsageTest" MaximumWidgets="12" MinimumWidgets="9" />
  ...

{: .callout .note}

NOTE

  • RecordProperty()Test クラスの静的メンバです。そのため の外部で使用する場合は、プレフィックスとして ::testing::Test:: を付ける必要があります。 そのため、 TEST 本体とテストフィクスチャークラスの外で使用する場合は、先頭に ::testing::test:: を付ける必要があります。
  • key は有効な XML 属性名でなければならず、googlet が既に使用しているものと衝突することはできません。
  • key は有効な XML 属性名であり、googletest が既に使用しているもの (name, status, time, classname. > と衝突することはできません。

type_param, and value_param) と衝突することはできません。

  • RecordProperty() をテストのライフスパン外に呼び出すことは可能です。 もし、テストの外側で、テストスイートの SetUpTestSuite()TearDownTestSuite() メソッドの間で呼び出された場合、そのテストは テストスイート用の XML 要素に帰属します。もし、すべてのテストスイートの外から呼び出された場合 テストスイートの外から呼び出された場合 (例: テスト環境内)、トップレベルの XML 要素に帰着します。 トップレベルの XML 要素に帰属する。

同一テストスイート内のテスト間でリソースを共有する

googletest はテストの独立性を高めるために、それぞれのテストに対して新しいテストフィクスチャオブジェクトを作成します。 を作成します。しかし、時にはテストがリソースを使うこともあります。 を使うこともあり、その場合は 1 回のテストにつき 1 コピーというモデルは法外に高くつきます。 になります。

テストがリソースを変更しないのであれば、1つのリソースのコピーを共有しても問題はありません。 を共有しても問題ありません。テスト単位のセットアップ/ティアダウンに加え、googletest はテストスイート単位でのセットアップ/ティアダウンもサポートしています。使うには

  1. テストフィクスチャのクラス (例えば FooTest ) で、いくつかのメンバ変数を static として宣言します。 として宣言します。
    1. テストフィクスチャークラスの外側 (通常はクラスのすぐ下) で、これらのメンバ変数を定義します。
    2. テストフィクスチャークラスの外側で (通常はそのすぐ下で)、それらのメンバ変数を定義します。オプションで初期値を与えることもできます。
    1. 同じテストフィクスチャクラスの中で、static void SetUpTestSuite() 関数を定義します(SetupTestSuite() という綴りは使わないでください)。 関数 (SetupTestSuite** のように、小さな u をつけて綴らないように注意してください!) を定義します。 と綴らないように注意してください!) を定義し、共有リソースをセットアップし、 static void TearDownTestSuite() を定義します。 関数があります。

それだけです!googletest は自動的に SetUpTestSuite() を呼び出して、FooTest テストスイートの *最初の * テストを実行する前に SetUpTestSuite() を呼び出します。 *を自動的に呼び出します。 を呼び出し、その中の 最後のテスト を実行した後で (つまり、最初の FooTest オブジェクトを作成した後で) TearDownTestSuite() を呼び出します。 を実行した後 (つまり、最後の FooTest オブジェクトを削除した後) に、 TearDownTestSuite() を呼び出します。その間に、テストは共有リソースを使用することができます。 は共有リソースを使用することができます。

テストの順番は未定義であることを忘れないでください。 に依存してはいけません。また、テストは共有リソースの状態を変更しないようにしなければなりません。 を変更してはいけませんし、もし変更した場合は、次のテストに制御を移す前に を元の値に戻してから次のテストに移行しなければなりません。

派生クラスを持つテストフィクスチャクラスでは、 SetUpTestSuite() が複数回呼ばれる可能性があることに注意してください。 は、派生クラスを持つテストフィクスチャのクラスでは複数回呼ばれる可能性があることに注意しましょう。 のコードが一度だけ実行されることを期待してはいけません。また、派生クラスは static メンバとして定義された共有リソースにアクセスすることができます。 また、派生クラスは static メンバとして定義された共有リソースにアクセスすることができます。 共有リソースの管理には十分な配慮が必要です。

ここでは、テストスイートごとのセットアップと撤収の例をご紹介します。

class FooTest : public testing::Test {
 protected:
  // テストスイートごとのセットアップ。
  // このテストスイートの最初のテストの前に呼び出されます。
  // 不要なら省略可能。
  static void SetUpTestSuite() {
    // FooTest のサブクラスで呼び出された場合は、静的オブジェクトの再割り当てを回避します。
    if (shared_resource_ == nullptr) { .
      shared_resource_ = new ...;
    }
  

  // テストスイートごとのティアダウン。
  // このテストスイートの最後のテストの後にコールされる。
  // 不要なら省略可能。
  static void TearDownTestSuite() {
    delete shared_resource_;
    shared_resource_ = nullptr;
  }

  // テストごとのセットアップロジックを通常通り定義することができます。
  void SetUp() override { ... }

  // テストごとのティアダウンロジックを通常通り定義することができます。
  void TearDown() override { ... }

  // 全てのテストで共有される高価なリソースがあります。
  static T* shared_resource_;
};

T* FooTest::shared_resource_ = nullptr;

TEST_F(FooTest, Test1) {
  ... shared_resource_ はこちらで参照できます ...


TEST_F(FooTest, Test2) {
  ... shared_resource_ はこちらで参照できます ...
}

{: .callout .note} NOTE: 上記のコードでは SetUpTestSuite() を protected と宣言していますが、SetUpTestSuite() を public と宣言する必要があるかもしれません。 と一緒に使う場合など、publicに宣言する必要がある場合があります。 TEST_P と共に使用する場合などです。

#グローバルセットアップとティアダウン

テストレベルやテストスイートレベルでセットアップとティアダウンができるように、テストプログラムレベルでも と同じように、テストプログラムのレベルでも行うことができます。その方法を説明します。

まず、::testing::Environment クラスをサブクラス化し、テスト環境を定義します。 環境を定義します。

class Environment : public ::testing::Environment {
 public:
  ~Environment() override {}

  // これをオーバーライドして、環境の設定方法を定義します。
  void SetUp() override {}

  // これをオーバーライドして、環境の撤去方法を定義します。
  void TearDown() override {}
};

そして、次のようにして環境クラスのインスタンスを googletest に登録します。 関数 ::testing::AddGlobalTestEnvironment() を呼び出すことで、環境クラスのインスタンスを googletest に登録します。

Environment* AddGlobalTestEnvironment(Environment* env);

さて、RUN_ALL_TESTS() が呼ばれると、まず各環境オブジェクトの SetUp() メソッドを呼び出します。 メソッドを呼び出した後、テストを実行します。 が致命的な失敗を報告せず、かつ GTEST_SKIP() が呼び出されていない場合にテストを実行します。run_all_tests() を実行します。 は、テストが実行されたかどうかに関係なく、常に各環境オブジェクトで TearDown() を呼び出します。 を呼び出します。

複数の環境オブジェクトを登録してもかまいません。このスイートでは、それらの SetUp() は登録された順に呼ばれます。 は登録された順に呼ばれ、TearDown() は逆の順番で呼ばれます。 は逆の順序で呼び出されます。

なお、登録された環境オブジェクトはgoogletestが所有権を持ちます。 そのため、自分で削除しないでください

RUN_ALL_TESTS()が呼ばれる前にAddGlobalTestEnvironment()を呼び出す必要があります。 おそらくmain() の中で呼び出すことになるでしょう。もし、gtest_main を使用する場合は、main()が始まる前にこれを呼び出す必要があります。 を使用する場合は、main()` が始まる前にこれを呼び出す必要があります。これを行う一つの方法として、グローバルな 変数を定義することです。

testing::Environment* const foo_env =
    testing::AddGlobalTestEnvironment(new FooEnvironment);

しかし、自分で main() を書いて、そこで AddGlobalTestEnvironment() を呼び出すことを強くお勧めします。 グローバル変数の初期化に依存すると、コードが読みにくくなります。 グローバル変数の初期化に依存すると、コードが読みにくくなりますし、異なる翻訳単位で複数の環境を登録した場合に問題が発生する可能性があります。 複数の環境を異なる翻訳単位で登録し、その環境間で というのは、グローバル変数の初期化に依存すると、コードが読みづらくなるし、異なる翻訳単位で複数の環境を登録し、その環境に依存性がある場合、問題が発生する可能性があるからです。 を保証しないことを忘れないでください)。

Value-Parameterized Tests (バリューパラメータ化テスト)

*値パラメータ化されたテストは、同じテストを何度も書くことなく、異なるパラメータでコードをテストすることができます。 同じテストを何度も書くことなく、異なるパラメータでコードをテストすることができます。これは次のような場面で役に立ちます。 これは様々な場面で有効です。

  • 1つまたは複数のコマンドラインフラグによって動作が影響されるコード片があります。 コマンドラインフラグの影響を受けるコードがあります。あなたのコードが、これらのフラグの様々な値に対して正しく動作することを確認したい。 これらのフラグの様々な値に対して、あなたのコードが正しく動作することを確認したい。
  • ある OO インターフェースの様々な実装をテストしたい。
  • 様々な入力に対してコードをテストしたい (いわゆるデータ駆動型テスト)。 この機能は悪用されやすいので、良識を持って使用してください。 この機能は悪用されやすいので、良識を働かせて使ってください。

値パラメタ化されたテストの書き方

値パラメータ化されたテストを書くには、まずフィクスチャークラスを定義します。これは は testing::Testtesting::WithParamInterface<T> の両方から派生したものでなければなりません。 (後者は純粋なインターフェイスです)。 の値の型です。便宜上、フィクスチャークラスを このクラスは testing::Testtesting::WithParam<T> の両方から派生しています。 と testing::WithParamInterface<T> の両方から派生したものです。T` はコピー可能な任意の型にすることができます。もし、それが 生ポインタの場合、ポインタの値の寿命を管理する責任があります。 の値の寿命を管理する責任があります。

{: .callout .note} NOTE: あなたのテストフィクスチャが SetUpTestSuite()TearDownTestSuite() を定義している場合、そのテストフィクスチャを使うには protected ではなく public と宣言しなければなりません。 を使うには、 protected ではなく public と宣言しなければなりません。 TEST_P` を使用するためには、これらは protected ではなく public と宣言されている必要があります。

class FooTest :
    public testing::TestWithParam<const char*> {
  // 通常のフィクスチャークラスのメンバをすべてここで実装することができます。
  // テストパラメータにアクセスするために、クラスから GetParam() を呼び出します。
  // TestWithParam<T> を呼び出します。
};

// あるいは、既存のフィクスチャークラスにパラメータを追加したい場合。
class BaseTest : public testing::Test { ...
  ...
};
class BarTest : public BaseTest,
                public testing::WithParamInterface<const char*> {
  ...
};

それから、TEST_P マクロを使って、このフィクスチャを使ったテストパターンをいくつでも定義します。 を使って好きなだけテストパターンを定義します。サフィックスの _P は "parameterized" または "pattern" を表し、どちらか好きな方を選んでください。 という意味です。

TEST_P(FooTest, DoesBlah) {
  // テスト内部では、テストパラメータに GetParam() メソッドでアクセスします。
  // TestWithParam<T> クラスの GetParam() メソッドでアクセスします。
  EXPECT_TRUE(foo.Blah(GetParam()));
  ...
}

TEST_P(FooTest, HasBlahBlah) {
  ...

最後に、INSTANTIATE_TEST_SUITE_P マクロを使用して、任意のパラメータでテストスイートをインスタンス化することができます。 マクロを使用して、任意のパラメータを指定してテストスイートを作成します。GoogleTest では、テストパラメータを生成するためのいくつかの関数を定義しています。 関数を定義しています。 (reference/testing.md#INSTANTIATE_TEST_SUITE_P) を参照ください。 にあります。

例えば、以下の文は FooTest テストスイートからテストをインスタンス化します。 テストスイートから、それぞれ "meeny", "miny", "moe" というパラメータを持つテストを生成します。 (reference/testing.md#param-generators) パラメータジェネレータを使用して、FooTest テストスイートからそれぞれのテストをインスタンス化します。

INSTANTIATE_TEST_SUITE_P(MeenyMinyMoe,
                         FooTest,
                         testing::Values("meeny", "miny", "moe"));

{: .callout .note} 注:上記のコードは、グローバルスコープまたは名前空間スコープに配置する必要があり、関数スコープには配置してはいけません。 関数スコープではありません。

INSTANTIATE_TEST_SUITE_P` の最初の引数は、テストスイートのインスタンスを作成するための一意な名前です。 のインスタンスの一意な名前です。次の引数はテストパターンの名前です。 パターン、そして最後の引数は パラメータジェネレータ です。

パラメータジェネレータの式は、GoogleTest が (InitGoogleTest() で) 初期化されるまでは評価されません。 が (InitGoogleTest() で) 初期化されるまでは評価されません。で初期化されるまでは評価されません。 main` 関数で行った事前の初期化は、 パラメータジェネレータからアクセスできるようになります。 フラグのパース結果などです。

テストパターンは複数回インスタンス化することができるので、そのインスタンスを区別するために パターンのインスタンスを複数回作成することができます。 をプレフィックスとして追加します。異なるインスタンスのために一意なプレフィックスを選ぶことを忘れないでください。 をつけることを忘れないようにしましょう。上のインスタンス化のテストは、このような名前になります。

  • MeenyMinyMoe/FooTest.DoesBlah/0 for "meeny"
  • MeenyMinyMoe/FooTest.DoesBlah/1 for "miny"
  • MeenyMinyMoe/FooTest.DoesBlah/2 for "moe"
  • MeenyMinyMoe/FooTest.HasBlahBlah/0 for "meeny"
  • MeenyMinyMoe/FooTest.HasBlahBlah/1 for "miny"
  • MeenyMinyMoe/FooTest.HasBlahBlah/2 for "moe"

これらの名前は [--gtest_filter](#running-a-subset of the-tests) で使用することができます。

次の文は、FooTest からすべてのテストをインスタンス化します。 を使ったパラメータ値 "cat""dog" でインスタンス化します。 (reference/testing.md#param-generators) パラメータジェネレータを使用して、 ValuesIn] (参照/testing.md#param-generators) のパラメータ値を指定しています。

const char* pets[] = {"cat", "dog"};
INSTANTIATE_TEST_SUITE_P(Pets, FooTest, testing::ValuesIn(pets));

上記のインスタンス化によるテストは、これらの名前を持つことになります。

  • Pets/FooTest.DoesBlah/0 for "cat"
  • Pets/FooTest.DoesBlah/1 for "dog"
  • Pets/FooTest.HasBlahBlah/0 for "cat"
  • Pets/FooTest.HasBlahBlah/1 for "dog"

INSTANTIATE_TEST_SUITE_P は、与えられたテストスイート内の *すべての* テストをインスタンス化することに注意しましょう。 の前後を問わず、与えられたテストスイート内の *すべての* テストをインスタンス化します。 INSTANTIATE_TEST_SUITE_P 文の前後を問わず、与えられたテストスイート内の すべての テストをインスタンス化することに注意してください。

さらに、デフォルトでは、すべての TEST_P に対応する INSTANTIATE_TEST_SUITE_P がなければ、テストスイートは失敗します。 INSTANTIATE_TEST_SUITE_P がない場合は、テストスイート GoogleTestVerification を使用します。この省略がエラーにならないようなテストスイートがある場合、たとえばそのテストスイートが 例えば、他の理由でリンクされているライブラリであったり、 テストケースのリストが動的であったりなどです。 テストケースのリストが動的であり、空である可能性がある場合、このチェックを抑制することができます。 テストスイートにタグをつけることで、このチェックを抑制することができます。

GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(FooTest);

他の例として sample7_unittest.ccsample8_unittest.cc を参照してください。

値パラメタ化された抽象テストの作成

上記では、FooTest同じ ソースファイル内で定義し、インスタンス化しています。 時には、値のパラメータ化されたテストをライブラリで定義しておき、後で他の人がそれをインスタンス化できるようにしたいと思うかもしれません。 を定義しておき、後からインスタンス化することもできます。このようなパターンは 抽象テスト と呼ばれます。 その応用例として、インターフェースを設計する際に 標準的な抽象テスト群 (おそらくファクトリ関数をテストのパラメータとして使用します) を作成します。 そのインターフェイスのすべての実装がパスすることが期待されるような、 標準的な抽象テスト群 (おそらくファクトリ関数をテストパラメータとして使用します) を書くことができます。 を書くことができます。誰かがそのインターフェイスを実装したら、テストスイートをインスタンス化することで をインスタンス化し、すべてのインターフェイス適合性テストを無料で取得することができます。

抽象的なテストを定義するには、次のようにコードを整理する必要があります。

  1. パラメータ化されたテストフィクスチャークラス (例: FooTest) の定義をヘッダーファイルに記述します。 をヘッダーファイル、例えば foo_param_test.h に記述します。これは、抽象的なテストを 宣言 しているのだと考えてください。 抽象的なテストを宣言することだと考えてください。
    1. TEST_P の定義を foo_param_test.cc に記述してください。 このファイルは foo_param_test.h を含んでいます。これは、抽象的なテストを実装することだと考えてください。

一度定義すれば、foo_param_test.h をインクルードすることでインスタンス化することができます。 INSTANTIATE_TEST_SUITE_P()を起動し、foo_param_test.ccを含むライブラリターゲットに依存することで、インスタンスを作成することができます。 をインクルードし、foo_param_test.cc` を含むライブラリターゲットに依存します。同じ抽象的なテストスイートを複数回インスタンス化することができます。 同じ抽象テストスイートを複数回インスタンス化することができます。

値パラメータ化されたテストパラメータの名称指定

INSTANTIATE_TEST_SUITE_P() の最後の引数はオプションで、ユーザは以下のように指定できます。 関数やファンクタを指定して、テストパラメータに基づいた独自のテスト名接尾辞を生成することができます。 を指定することができます。この関数は、以下のような型の引数をひとつ受け取ります。 testing::TestParamInfo<class ParamType> という型の引数を一つ受け取り、 std::string を返します。

testing::PrintToStringParamNameは、ビルトインのテストサフィックスジェネレータで、testing::PrintToString(GetParam())の値を返します。 は、testing::PrintToString(GetParam()) の値を返します。には使えません。 std::string や C の文字列に対しては動作しません。

{: .callout .note} 注:テスト名は空であってはならず、ユニークでなければなりません。 の英数字のみを含むことができます。特に アンダースコアを含んではいけません

class MyTestSuite : public testing::TestWithParam<int> {};

TEST_P(MyTestSuite, MyTest)
{
  std::cout << "Example Test Param: " << GetParam() << std::endl;
}

INSTANTIATE_TEST_SUITE_P(MyGroup, MyTestSuite, testing::Range(0, 10),
                         testing::PrintToStringParamName());

カスタムファンクタを提供することで、テストパラメータ名の生成をより細かく制御することができます。 特に、自動変換では有用なパラメータ名が生成されないような型ではそうです。 特に、自動変換が有用なパラメータ名を生成しない型 (例えば、上で示したような文字列) の場合は、テストパラメータ名の生成をより細かく制御できるようになります。次の例は、複数のパラメータを持つ 次の例は、複数のパラメータ、列挙型、および文字列について説明しています。 と文字列という複数のパラメータについて説明し、 ジェネレータを組み合わせる方法も示しています。この例では、簡潔にするためにラムダ を使っています。

enum class MyType { MY_FOO = 0, MY_BAR = 1 };

class MyTestSuite : public testing::TestWithParam<std::tuple<MyType, std::string>> {
};

INSTANTIATE_TEST_SUITE_P(
    MyGroup, MyTestSuite,
    testing::Combine(
        testing::Values(MyType::MY_FOO, MyType::MY_BAR),
        testing::Values("A", "B")),
    [](const testing::TestParamInfo<MyTestSuite::ParamType>& info) {
      std::string name = absl::StrCat(
          std::get<0>(info.param) == MyType::MY_FOO ? "Foo" : "Bar",
          std::get<1>(info.param));
      absl::c_replace_if(name, [](char c) { return !std::isalnum(c); }, '_');
      return name;
    });

Typed Tests

同じインタフェースの実装が複数あり、それらが共通の要件を満たすことを確認したいとします。 を実装し、それらが共通の要求を満たすことを確認したいとします。あるいは あるいは、同じ「概念」に適合するはずの複数の型を定義し、それを検証したい。 を検証したい場合もあります。どちらの場合も、同じテストロジックを異なる型に対して繰り返し実行させたい を繰り返したい。

テストしたい型ごとに TESTTEST_F を書くことはできますが ( テストロジックを関数テンプレートに組み込んで、その関数から呼び出すこともできます。 から呼び出す関数テンプレートにテストロジックを組み込むこともできます) が、これは面倒でスケールしません。 の型に対して m 個のテストを行いたい場合、結局は m*n 個の TEST を書くことになります。

型付きテストは、型のリストに対して同じテストロジックを繰り返すことができます。あなたは テストロジックは一度だけ記述すればよいのですが、型付きテストを記述する際には型リストを知っておく必要があります。 を知っている必要があります。以下はその方法です。

まず、フィクスチャークラスのテンプレートを定義します。これは型によってパラメータ化される必要があります。 このクラスは ::testing::Test から派生させることを忘れないでください。

template <typename T>
class FooTest : public testing::Test {
 public:
  ...
  using List = std::list<T>;
  static T shared_;
  T value_;
};

次に、型のリストとテストスイートを関連付けて、リストの各型に対して繰り返されます。 を繰り返します。

using MyTypes = ::testing::Types<char, int, unsigned int>;
TYPED_TEST_SUITE(FooTest, MyTypes);

型のエイリアス (using または typedef) は、 TYPED_TEST_SUITE マクロが正しくパースできるようにするために必要なものです。 マクロが正しくパースするために必要です。そうでないと、コンパイラは型リストの各カンマが新しいマクロ引数を導入していると判断してしまいます。 のコンマが新しいマクロ引数を導入しているとコンパイラが判断してしまいます。

そして、 TEST_F() の代わりに TYPED_TEST() を使って、このテストスイートに対する型付けされたテストを定義してください。 を定義します。これを何度でも繰り返すことができます。

TYPED_TEST(FooTest, DoesBlah) {
  // テスト内部では、TypeParam という特殊な名前を参照して、型パラメータを取得します。
  // パラメータを取得します。  派生クラステンプレートの中にいるので、C++ は FooTest のメンバにアクセスすることを要求します。
  // FooTest のメンバを 'this' 経由で参照する必要があります.
  TypeParam n = this->value_;

  // フィクスチャの静的メンバを訪問するには、'TestFixture::' を追加します。
  // 接頭辞をつけます。
  n += TestFixture::shared_;

  // フィクスチャ内の型定義を参照するには、'typename TestFixture::' を追加します。
  // 接頭辞を付けます。  typename' はコンパイラを満足させるために必要です。
  typename TestFixture::List values;

  values.push_back(n);
  ...
}

TYPED_TEST(FooTest, HasPropertyA) { ... }

完全な例はsample6_unittest.ccを参照してください。

Type-Parameterized Tests (タイプパラメータ化テスト)

型パラメタライズドテストは型付けされたテストに似ていますが、前もって型のリストを知っておく必要がない点が異なります。 型付けされたテストと似ていますが、前もって型のリストを知っておく必要がありません。そのかわり、テストロジックを最初に定義して ロジックを定義し、後でそれを異なる型リストでインスタンス化することができます。さらに 同じプログラムの中で複数回インスタンス化することもできます。

インターフェイスやコンセプトを設計する場合、以下のような一連のテストを定義することができます。 を定義し、その実装が持つべき特性を検証することができます。 を定義することができます。そして、各実装の作者は をインスタンス化するだけで、その実装が要件に適合しているかどうかを検証することができます。 を検証することができます。以下はその例です。 の例です。

まず、型付けされたテストのときと同じように、フィクスチャークラスのテンプレートを定義します。

template <typename T>
class FooTest : public testing::Test {
  void DoSomethingInteresting();
  ...
};

次に、型パラメタ化されたテストスイートを定義することを宣言します。

TYPED_TEST_SUITE_P(FooTest);

そして、TYPED_TEST_P() を使って、型パラメタ化されたテストを定義します。これを何度でも繰り返すことができます。 これを何度でも繰り返すことができます。

TYPED_TEST_P(FooTest, DoesBlah) {
  // テスト内部では、TypeParam を参照して、型パラメータを取得します。
  TypeParam n = 0;

  // フィクスチャメンバーを参照するには、明示的に `this` を使用する必要があります。
  this->DoSomethingInteresting()
  ...
}

TYPED_TEST_P(FooTest, HasPropertyA) { ... }

さて、ここで厄介なことがあります。 マクロを使用してテストパターンを登録する必要があります。マクロの最初の マクロの最初の引数はテストスイート名で、残りの引数はこのテストスイートのテストの名前です。 残りの部分はこのテストスイート内のテストの名前です。

REGISTER_TYPED_TEST_SUITE_P(FooTest,
                            DoesBlah, HasPropertyA);

最後に、このパターンを好きな型でインスタンス化するのは自由である。もし 上記のコードをヘッダーファイルに記述すれば、複数の C++ ソースファイルに #include して、何度もインスタンス化することができます。 のソースファイルに #include して、何度もインスタンス化することができます。

using MyTypes = ::testing::Types<char, int, unsigned int>;
INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, MyTypes);

パターンの異なるインスタンスを区別するために、INSTANTIATE_TYPED_TEST_SUITE_Pマクロの最初の引数は、そのパターンに追加されるプレフィックスです。 INSTANTIATE_TYPED_TEST_SUITE_P` マクロの最初の引数はプレフィックスで、 これは実際のテストスイートの名前に追加されます。 マクロの最初の引数は、実際のテストスイート名に付加されるプレフィックスです。異なるインスタンスのためにユニークなプレフィックスを選ぶことを覚えておいてください。 を選ぶことを忘れないでください。

型リストに含まれる型が1つだけという特殊な場合、次のように ::testing::types<... > を使わずに直接その型を書くことができます。 のように ::testing::Types<...> を使わずに直接その型を書くことができます。

INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, int);

完全な例はsample6_unittest.ccを参照してください。

プライベートコードのテスト

ソフトウェアの内部実装を変更しても、ユーザがその変更に気づかない限り、テストが壊れることはありません。 テストが壊れることはありません。したがって、**ブラックボックステストの原則に従って ブラックボックステストの原則に従って、ほとんどの場合、コードを公開インターフェースを通してテストする必要があります。 を通してテストする必要があります。

**それでもなお、内部実装コードをテストする必要があると感じた場合。 よりよい設計があるかどうか考えてみてください。 をテストしたいという欲求は、しばしばそのクラスがあまりにも多くのことをやっているというサインです。検討 実装クラスを抽出し、それをテストします。そして、その実装クラスを元のクラスで使用します。 を元のクラスで使用します。

しかし、どうしても非公開のインターフェースのコードをテストしなければならない場合は、テストすることができます。それには は、2つのケースを考慮する必要があります。

  • 静的関数(静的メンバ関数と同じではありません!)または無名名前空間 名前空間、および
  • プライベートまたはプロテクトされたクラス・メンバー

それらを検証するために、以下のような特殊な技術を使用しています。

  • 静的関数も無名名前空間での定義・宣言も、同じ翻訳単位内でのみ見ることができます。 は、同じ翻訳ユニット内でのみ見ることができます。これらをテストするには、次のようにします。 テストする .cc ファイル全体を *_test.cc ファイルに #include してください。 (.cc ファイルをインクルードすることは、コードを再利用するための良い方法ではありません。 をインクルードしてはいけません!)

    しかし、よりよい方法は、プライベートなコードを ここで、foo はあなたのプロジェクトが通常使用する名前空間です。 ここで、foo はあなたのプロジェクトが通常使用する名前空間です。そして、プライベートな宣言は *-internal.h ファイルに記述してください。 制作用の .cc ファイルとテストは、この内部ヘッダーをインクルードすることができます。 内部ヘッダを含むことができますが、クライアントはそうではありません。この方法では、内部実装を完全にテストすることができます。 この方法では、クライアントに漏らすことなく、内部の実装を完全にテストすることができます。

  • プライベートクラスのメンバーには、クラス内または友達からのみアクセスできます。 のみアクセス可能です。クラスのプライベートなメンバにアクセスするには、 テストフィクスチャをクラスのフレンドとして宣言し、 フィクスチャの中でアクセサを定義します。 フィクスチャをクラスの友人として宣言し、 フィクスチャの中でアクセサを定義します。フィクスチャを使用したテスト はそのクラスのプライベートメンバにアクセスすることができます。 のプライベートメンバにアクセスできるようになります。フィクスチャ がそのクラスの友人であったとしても、 テストは自動的にそのクラスの友人となるわけではありません。 フィクスチャのサブクラスで定義されているので、自動的にフレンドになるわけではありません。 のサブクラスで定義されるからです。

    プライベートメンバをテストするもう一つの方法は、プライベートメンバを実装クラスにリファクタリングすることです。 このクラスは *-internal.h ファイルで宣言されます。このヘッダは クライアントはこのヘッダを含めることができませんが、テストでは可能です。このようなものは と呼ばれるものです。 Pimpl (Private Implementation) イディオムです。

    あるいは、個々のテストをクラスの友人として宣言するには、次の行を追加します。 を追加することで、個々のテストをクラスの友人として宣言することもできます。

        FRIEND_TEST(TestSuiteName, TestName);

    例えば、こんな感じです。

    // foo.h
    class Foo {
      ...
     private:
      FRIEND_TEST(FooTest, BarReturnsZeroOnNull);
    
      int Bar(void* x);
    };
    
    // foo_test.cc
    ...
    TEST(FooTest, BarReturnsZeroOnNull) {
      Foo foo;
      EXPECT_EQ(foo.Bar(NULL), 0);  // Uses Foo's private member Bar().
    }

    クラスが名前空間の中で定義されている場合は、特に注意が必要です。もし テストフィクスチャやテストをクラスの友人としたいのなら、 それらはまったく同じ名前空間で定義されていなければなりません。 で定義されている必要があります (匿名空間やインライン空間では定義できません)。

    例えば、テストするコードが以下のようなものであった場合。

    namespace my_namespace {
    
    class Foo {
      friend class FooTest;
      FRIEND_TEST(FooTest, Bar);
      FRIEND_TEST(FooTest, Baz);
      ... definition of the class Foo ...
    };
    
    }  // namespace my_namespace

    Your test code should be something like:

    namespace my_namespace {
    
    class FooTest : public testing::Test {
     protected:
      ...
    };
    
    TEST_F(FooTest, Bar) { ... }
    TEST_F(FooTest, Baz) { ... }
    
    }  // namespace my_namespace

失敗を "キャッチ "する

googletest の上にテスト用ユーティリティを構築している場合、そのユーティリティをテストしたいと思うことでしょう。 ユーティリティをテストしたいと思うでしょう。それをテストするためにどんなフレームワークを使いますか? もちろん、googletestです。

課題は、テストユーティリティが正しく失敗を報告することを検証することです。 例外をスローすることで失敗を報告するフレームワークでは、例外をキャッチし をキャッチしてその上でアサートできます。しかし googletest は例外を使わないので、どのようにして コードの一部が期待された失敗を生成することをテストするのでしょうか?

gtest/gtest-spi.h"`には、これを実現するためのいくつかの構文が含まれています。 このヘッダをインクルードした後は

  EXPECT_FATAL_FAILURE(statement, substring);

を使用して、 statement が致命的な (例えば ASSERT_*) 失敗を発生させることを表明します。 を生成することを表明するか、あるいは、与えられた substring を含むメッセージの

  EXPECT_NONFATAL_FAILURE(statement, substring);

は、致命的でない (例えば EXPECT_*) 失敗を予期している場合です。

現在のスレッドの失敗だけをチェックして、このタイプの期待値の結果を決定します。 の結果を決定します。もし statement が新しいスレッドを作成したら、そのスレッドでの失敗も無視されます。 の失敗も無視される。他のスレッドでの失敗もキャッチしたい場合は、代わりに次のようなマクロを使用します。 他のスレッドでの失敗もキャッチしたい場合は、代わりに以下のマクロのいずれかを使用します。

  EXPECT_FATAL_FAILURE_ON_ALL_THREADS(statement, substring);
  EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(statement, substring);

{: .callout .note} 注:現在、複数のスレッドからのアサーションはWindowsではサポートされていません。

技術的な理由により、いくつかの注意事項があります。

  1. どちらのマクロにも、失敗メッセージを流すことはできません。

  2. EXPECT_FATAL_FAILURE{_ON_ALL_THREADS}() 内の statementthis オブジェクトのローカル非静的変数や非静的メンバを参照することができません。 ローカルな非静的変数または this オブジェクトの非静的メンバを参照することはできません。

  3. EXPECT_FATAL_FAILURE{_ON_ALL_THREADS}() 内の statement は値を返すことができません。 値を返すことができません。

プログラムでテストを登録する

TEST マクロは、すべてのユースケースの大部分を扱いますが、ランタイム登録ロジックが必要なケースはほとんどありません。 ランタイムの登録ロジックが必要な場合があります。そのような場合のために、フレームワークは フレームワークは ::testing::RegisterTest を提供し、呼び出し元が任意のテストを動的に登録できるようにします。 テストを動的に登録することができます。

これは、TESTマクロでは不十分な場合にのみ使用する高度なAPIです。 マクロは、この関数を呼び出す際の複雑さをほとんど回避できるため、可能であれば優先的に使用すべきです。 この関数を呼び出す複雑さをほとんど避けることができるからです。

以下のようなシグネチャーが用意されています。

template <typename Factory>
TestInfo* RegisterTest(const char* test_suite_name, const char* test_name,
                       const char* type_param, const char* value_param,
                       const char* file, int line, Factory factory);

引数 factory はファクトリーコール可能な(移動構築可能な)オブジェクト、あるいは 関数ポインタで、テストオブジェクトの新しいインスタンスを作成します。これは の所有権を呼び出し元に渡します。callable のシグネチャは Fixture*() であり、ここで ここで Fixture はテストのフィクスチャクラスです。で登録されたすべてのテストは 同じ test_suite_name で登録されたすべてのテストは、同じフィクスチャタイプを返さなければなりません。これは実行時にチェックされます。 のランタイムでチェックされます。

フレームワークはファクトリーからフィクスチャークラスを推測し、そのクラスに対して SetUpTestSuiteTearDownTestSuite` を呼び出します。

RUN_ALL_TESTS()`が起動される前に呼び出されなければならない,さもなければ動作は未定義である. は未定義です。

ユースケース例

class MyFixture : public testing::Test {
 public:
  // All of these optional, just like in regular macro usage.
  static void SetUpTestSuite() { ... }
  static void TearDownTestSuite() { ... }
  void SetUp() override { ... }
  void TearDown() override { ... }
};

class MyTest : public MyFixture {
 public:
  explicit MyTest(int data) : data_(data) {}
  void TestBody() override { ... }

 private:
  int data_;
};

void RegisterMyTests(const std::vector<int>& values) {
  for (int v : values) {
    testing::RegisterTest(
        "MyFixture", ("Test" + std::to_string(v)).c_str(), nullptr,
        std::to_string(v).c_str(),
        __FILE__, __LINE__,
        // ここでは、フィクスチャタイプを戻り値の型として使うことが重要です。
        [=]() -> MyFixture* { return new MyTest(v); });
  }
}
...
int main(int argc, char** argv) {
  testing::InitGoogleTest(&argc, argv);
  std::vector<int> values_to_test = LoadValuesFromConfig();
  RegisterMyTests(values_to_test);
  ...
  return RUN_ALL_TESTS();
}

現在のテストの名前を取得する

時には、関数が現在実行中のテストの名前を知っておく必要があるかもしれません。 たとえば、テストフィクスチャの SetUp() メソッドを使用して、実行中のテストの名前を設定することができます。 メソッドを使用して、どのテストが実行されているかに基づいてゴールデンファイル名を設定することができます。その場合 (reference/testing.md#TestInfo) クラスは、この情報を持っています。

現在実行中のテストの TestInfo オブジェクトを取得するには、以下のようにコールします。 (reference/testing.md#UnitTest) を実行してください。 シングルトン・オブジェクトです。

  // 現在実行中のテストに関する情報を取得します。
  // 返されたオブジェクトは削除しないでください - UnitTest クラスによって管理されます。
  const testing::TestInfo* const test_info =
      testing::UnitTest::GetInstance()->current_test_info();

  printf("We are in test %s of test suite %s.\n",
         test_info->name(),
         test_info->test_suite_name());

現在テストが実行されていない場合は current_test_info() は NULL ポインタを返します。特に 特に、SetUpTestSuite() の中でテストスイート名を見つけることができません。 TearDownTestSuite()` (暗黙のうちにテストスイート名を知っている場合) や、そこから呼び出される関数では、特にテストスイート名を見つけることができません。 や、それらから呼び出される関数では見つけることができません。

テストイベントを処理することによる googletest の拡張

googletest は イベントリスナーAPI を提供し、テストプログラムの進行状況やテストの失敗に関する通知を受け取ることができます。 を提供しており、テストプログラムの進行状況やテストの失敗に関する通知を受け取ることができます。あなたが聞くことができるイベント テストプログラム、テストスイート、テストメソッドの開始や終了などです。 メソッドなどです。この API を使って、標準のコンソール出力を補強したり置き換えたりすることができます。 コンソール出力の補強や置き換え、XML 出力の置き換え、あるいは GUI などのまったく別の形式の出力に使用することができます。 を提供することもできます。また、テストイベントを をチェックポイントとして使用し、 リソースリークチェッカーを実装することもできます。

イベントリスナーの定義

イベントリスナーを定義するには、以下のいずれかのサブクラスを作成します。 イベントリスナーを定義するには、 [testing::TestEventListener] (reference/testing.md#TestEventListener) または または [testing::EmptyTestEventListener] (reference/testing.md#EmptyTestEventListener) のどちらかをサブクラス化します。 前者は (抽象的な) インターフェースで、 *各単純な仮想メソッドはテストイベントを処理するためにオーバーライドすることができます。 前者は (抽象的な) インターフェースで、テストイベントを処理するために 各純粋な仮想メソッドをオーバーライドできます (たとえば、テストが開始されると OnTestStart()` メソッドが呼び出されます)。後者は、インターフェイスの全メソッドの空の実装を提供します。 後者は、インターフェイスのすべてのメソッドの空の実装を提供し、サブクラスが必要とするのは をオーバーライドする必要があります。

イベントが発生すると、そのコンテキストがハンドラ関数に引数として渡されます。 引数としてハンドラ関数に渡されます。引数の種類は以下の通りである。

  • UnitTest は、テストプログラム全体の状態を反映します。
  • TestSuite はテストスイートに関する情報を持ち、1 つまたは複数のテストを含むことができます。 テストスイートは、1 つ以上のテストを含むことができます。
  • TestInfo は、テストの状態を表します。 TestInfo はテストの状態を含み、* TestPartResult はテストのアサーションの結果を表す。

イベントハンドラ関数は、受け取った引数を調べて、イベントとテストプログラムの状態に関する興味深い情報 イベントとテストプログラムの状態に関する興味深い情報を得ることができます。

以下はその一例です。

  class MinimalistPrinter : public testing::EmptyTestEventListener {
    // Called before a test starts.
    void OnTestStart(const testing::TestInfo& test_info) override {
      printf("*** Test %s.%s starting.\n",
             test_info.test_suite_name(), test_info.name());
    }

    // Called after a failed assertion or a SUCCESS().
    void OnTestPartResult(const testing::TestPartResult& test_part_result) override {
      printf("%s in %s:%d\n%s\n",
             test_part_result.failed() ? "*** Failure" : "Success",
             test_part_result.file_name(),
             test_part_result.line_number(),
             test_part_result.summary());
    }
    
    // Called after a test ends.
    void OnTestEnd(const testing::TestInfo& test_info) override {
      printf("*** Test %s.%s ending.\n",
             test_info.test_suite_name(), test_info.name());
    }
  };

イベントリスナーの使用

定義したイベントリスナーを使用するには、そのインスタンスを googletest のイベントリスナーリストに追加します。 TestEventListeners - 名前の最後に "s" があることに注意してください) のインスタンスを、googletest のイベントリスナーリストに追加します。 を呼び出す前に、main() 関数内で を呼び出す前に、 main() 関数内で実行します。

int main(int argc, char** argv) {
  testing::InitGoogleTest(&argc, argv);
  // Gets hold of the event listener list.
  testing::TestEventListeners& listeners =
      testing::UnitTest::GetInstance()->listeners();
  // Adds a listener to the end.  googletest takes the ownership.
  listeners.Append(new MinimalistPrinter);
  return RUN_ALL_TESTS();
}

ただ一つ問題があります。デフォルトのテスト結果プリンターがまだ有効なので その出力は、あなたのミニマリストプリンターからの出力と混ざり合ってしまいます。デフォルトのプリンターを抑制するには を抑制するには、イベントリスナーリストからそれを解放し、削除してください。 そのためには、1行追加すればOKです。

  ...
  delete listeners.Release(listeners.default_result_printer());
  listeners.Append(new MinimalistPrinter);
  return RUN_ALL_TESTS();

今までのテストとは全く違う出力をお楽しみください。詳しくは 詳細は sample9_unittest.cc を参照してください。

リストには複数のリスナーを追加することができます。OnStart() または On*Start() または OnTestPartResult() イベントが発生すると、リスナーはリストの順番でイベントを受け取ります。 新しいリスナーはリストの最後に追加されるため、リスナーはリストに表示された順にそれを受け取ります。 デフォルトのテキストプリンタとデフォルトのXMLジェネレータは、最初にイベントを受信します。 を最初に受け取ります)。OnEnd()` イベントが発生すると、リスナーは の順序でイベントを受信します。 の順番で受け取ります。これにより、後から追加されたリスナーからの出力が、先に追加されたリスナーからの出力によってフレームされることができます。 の出力に囲まれることができます。

リスナーで失敗を発生させる

イベント処理の際に、失敗を知らせるマクロ (EXPECT_*(), ASSERT_*(), FAIL(), etc) を使用することができます。 を使うことができます。ただし、いくつかの制約があります。

  1. OnTestPartResult()の中で失敗を発生させることはできません (そうでなければ、OnTestPartResult() が再帰的に呼び出されてしまいます)。 OnTestPartResult() が再帰的に呼び出される原因になります)。
    1. OnTestPartResult() を処理するリスナーは、いかなる失敗も発生させることはできません。 の失敗を防ぐことができます。

リスナーリストにリスナーを追加するときは、失敗を生成するリスナーの前に を処理するリスナーを、失敗を生成するリスナーの前に置くべきです。これは これは、後者によって生成された失敗が前者によって正しいテストに帰着することを保証します。 に帰属させることができます。

失敗を知らせるリスナーの例については sample10_unittest.cc を参照してください。

テストプログラムの実行高度なオプション

googletest のテストプログラムは普通の実行ファイルです。ビルドしたら、それらを直接実行することができます を直接実行し、以下の環境変数やコマンドラインフラグでその動作に影響を与えることができます。 とコマンドラインフラグを使用します。フラグを有効にするためには、あなたのプログラムは RUN_ALL_TESTS()を呼び出す前に::testing::InitGoogleTest()` を呼び出す必要があります。

サポートされているフラグとその使用法の一覧を見るには、テストプログラムを --help フラグで実行してください。 を --help フラグで実行してください。また、-h, -?, または /? を略して使用することもできます。

あるオプションが環境変数とフラグの両方で指定された場合、後者が優先されます。 が優先されます。

テストの選択

テスト名のリストアップ

あるプログラムを実行する前に、利用可能なテストの一覧を表示することが必要な場合があります。 必要であればフィルタをかけることができます。フラグ gtest_list_tests` を含めると、他のすべてのフラグを上書きして、次のような形式でテストをリストアップします。 の形式でテストをリストアップします。

TestSuite1.
  TestName1
  TestName2
TestSuite2.
  TestName

このフラグが指定された場合、リストアップされたテストはどれも実際には実行されません。このフラグに対応する環境変数はありません。 このフラグに対応する環境変数はありません。

テストのサブセットを実行する

デフォルトでは、googletest プログラムはユーザが定義したすべてのテストを実行します。時には テストのサブセットだけを実行したいこともあります (たとえば、デバッグのため、もしくはすばやく を検証するためなど)。もし、環境変数 GTEST_FILTER あるいは フラグにフィルタ文字列を設定すると、 googletest は以下のようなテストだけを実行します。 を設定すると、 googletest はそのフィルタにマッチするフルネーム (TestSuiteName.TestName の形式) のテストのみを実行します。

フィルタのフォーマットは、':'で区切られたワイルドカードパターン(positive patternsと呼ばれます)のリストです。 のリストです(これを positive patterns と呼びます) オプションとして、'- の後に別の で区切られたパターンリストです(ネガティブパターン と呼ばれます)。テストがフィルタにマッチするのは テストがフィルタにマッチするのは、正のパターンのいずれにもマッチし、かつ負のパターンのいずれにもマッチしない場合のみです。 にマッチし、かつネガティブパターンのいずれにもマッチしない場合にのみ、テストはフィルタにマッチします。

パターンは '*' (任意の文字列にマッチ) または '?' (任意の一文字にマッチ) を含むことができます。 (任意の一文字にマッチ) を含むことができます。便宜上、'*-NegativePatterns'というフィルタは '-NegativePatterns' と書くこともできます。 は '-NegativePatterns' とも書けます。

例えば、こんな感じです。

  • ./foo_test フラグがないので、すべてのテストが実行されます。
  • ./foo_test --gtest_filter=* また、すべてのテストが実行されます。 match-everything * という値によって、すべてのテストを実行します。
  • ./foo_test --gtest_filter=FooTest.* テストスイート内のすべてのテストを実行します。 FooTest .
  • ./foo_test --gtest_filter=*Null*:*Constructor* フルネームが "Null "*:*Constructor* を含むテストをすべて実行します。 が "Null"あるいは"Constructor"` のどちらかを含むテストを実行します。
  • ./foo_test --gtest_filter=-*DeathTest.* デス以外のすべてのテストを実行します。
  • ./foo_test --gtest_filter=FooTest.*-FooTest.Bar テストスイート FooTest に含まれる全てのテストを実行します。 テストスイート FooTestFooTest.Bar 以外を実行します。
  • ./foo_test --gtest_filter=FooTest.*:BarTest.*-FooTest.Bar:BarTest.Foo テストスイートを実行します。 テストスイート FooTest のうち、FooTest.Bar を除くすべてのテストと BarTest.Foo以外のテストスイート BarTest` のすべてを実行します。

最初の失敗でテストの実行を停止する

デフォルトでは、googletest プログラムはユーザーが定義したすべてのテストを実行します。いくつかの場合 場合によっては (テストの開発と実行を繰り返す場合など)、最初の失敗でテストの実行を停止することが望ましいかもしれません。 を停止させることが望ましい場合もあります (遅延の改善と完全性の交換)。 もし GTEST_FAIL_FAST 環境変数あるいは --gtest_fail_fast フラグが設定されている場合、テストランナーは最初の失敗が発生した時点で実行を停止します。 が設定されている場合、テストランナーは最初のテスト失敗が見つかるとすぐに実行を停止します。

テストの一時的な無効化

もし、すぐに修正できないような壊れたテストがある場合は、テスト名に DISABLED_というプレフィックスをつけます。これにより、そのテストは実行から除外されます。これは これは、コードをコメントアウトしたり#if 0` を使ったりするよりもよい方法です。 というのも、無効化されたテストはまだコンパイルされているからです (したがって、腐ることはありません)。

テストスイート内のすべてのテストを無効にする必要がある場合は、 各テストの名前の先頭に DISABLED_ を追加します。 を各テストの名前の前に追加するか、 あるいはテストスイートの名前の前に追加します。 を追加するか、あるいはテストスイート名の先頭に追加します。

たとえば、次のテストはコンパイルされても googletest では実行されません。 は実行されません。

// Tests that Foo does Abc.
TEST(FooTest, DISABLED_DoesAbc) { ... }

class DISABLED_BarTest : public testing::Test { ... };

// Tests that Bar does Xyz.
TEST_F(DISABLED_BarTest, DoesXyz) { ... }

{: .callout .note} 注意:この機能は一時的な苦痛を和らげるためにのみ使用してください。その場合でも を修正する必要があります。注意点として、googletest はテストプログラムに無効なテストが含まれる場合、警告を表示します。 バナーを表示します。

{: .callout .tip} ヒント: 無効化されたテストの数を簡単に数えるには を使って簡単に数えることができます。この数は、テストの品質を向上させるための指標として使うことができます。 テストの品質を向上させるための指標として使うことができます。

無効なテストの一時的な有効化

無効化されたテストをテストの実行に含めるには、テストプログラムに フラグを立ててテストプログラムを起動するか、あるいは GTEST_ALSO_RUN_DISABLED_TESTS環境変数を0以外の値に設定してください。 このフラグと--gtest_filter` フラグを組み合わせることで、実行する無効なテストをさらに選択することができます。 フラグと組み合わせて、実行するテストを選択することができます。

テストの繰り返し

時々、結果がヒットするかしないかのテストに遭遇することがあります。もしかしたら その場合、デバッガでバグを再現するのはかなり難しくなります。 デバッガでバグを再現することは困難です。これは大きなフラストレーションの原因になり得ます。

gtest_repeat` フラグを使うと、プログラム中のすべての (あるいは選択した) テストメソッドを何度も繰り返すことができます。 を何度も繰り返すことができます。うまくいけば、欠陥のあるテストが最終的に失敗し、デバッグの機会を得ることができます。 デバッグする機会を与えてくれます。以下はその使い方です。

$ foo_test --gtest_repeat=1000
Repeat foo_test 1000 times and don't stop at failures.

$ foo_test --gtest_repeat=-1
A negative count means repeating forever.

$ foo_test --gtest_repeat=1000 --gtest_break_on_failure
Repeat foo_test 1000 times, stopping at the first failure.  This
is especially useful when running under a debugger: when the test
fails, it will drop into the debugger and you can then inspect
variables and stacks.

$ foo_test --gtest_repeat=1000 --gtest_filter=FooBar.*
Repeat the tests whose name matches the filter 1000 times.

テストプログラムに グローバルセットアップ/ティアダウンコードが含まれている場合、そのコードも反復されることになります。 が含まれている場合、各反復処理でそのコードが繰り返されます。これを避けるために グローバルセットアップとティアダウンを繰り返さないようにするには、次のように指定します。 --gtest_recreate_environments_when_repeating=false{.nowrap}.

また、環境変数 GTEST_REPEAT を設定することで、繰り返し回数を指定することができます。 変数で指定することもできます。

テストのシャッフル

gtest_shuffleフラグを指定する (あるいはGTEST_SHUFFLE環境変数を設定する) ことで、プログラム中のテストをランダムに実行することができます。 環境変数を1` に設定します) を指定すると、プログラムの中のテストをランダムな順番で実行することができます。 これは、テスト間の悪い依存関係を明らかにするのに役立ちます。

デフォルトでは、googletest は現在の時間から計算されたランダムシードを使用します。 そのため、毎回異なる順番になります。コンソールの出力には ランダムシードの値を含むので、順序に関連するテストの失敗を後で再現することができます を後で再現できるようになります。乱数種を明示的に指定するには、 --gtest_random_seed=SEED フラグを使用します(あるいは GTest_random_seed=SEED に設定します)。 フラグを使用します (または、環境変数 GTEST_RANDOM_SEED を設定します)。 SEED` は [0, 99999] の範囲にある整数です。シード値 0 は特別です。 googletest は現在の時刻からシードを計算するというデフォルトの動作をするように指示します。 時間からシードを計算するという、googletest のデフォルトの動作を指定します。

これを --gtest_repeat=N と組み合わせると、googletest はテストごとに異なるランダムな種を選びます。 を選び、各反復でテストをシャッフルします。

テスト機能を複数のマシンに分散させる

テストプログラムの実行に使用できるマシンが複数台ある場合、テスト機能を並列に実行し テスト関数を並列に実行し、より速く結果を得たいと思うかもしれません。このような手法を この手法を シャーディング と呼び、各マシンを シャード と呼びます。

GoogleTestは、テストシャーディングに対応しています。この機能を利用するために テストランナー (GoogleTest の一部ではない) は、次のようにする必要があります。

  1. テストを実行するためのマシン(シャード)を複数台割り当てる。
    1. 各シャードで、環境変数 GTEST_TOTAL_SHARDS にシャードの総数を設定します。 シャードの総数を設定します。これは、すべてのシャードで同じでなければなりません。
  2. 各シャードで、GTEST_SHARD_INDEX環境変数をシャードのインデックスに設定します。 を設定します。異なるシャードには、異なるインデックスを割り当てる必要があります。 0, GTEST_TOTAL_SHARDS - 1]`の範囲である必要があります。
  3. すべてのシャードで同じテストプログラムを実行する。GoogleTestが上記2つの環境変数を確認したら GoogleTest は上記の二つの環境変数を見て、実行するテスト関数のサブセットを選択します。 すべてのシャードで、プログラム中の各テスト関数が正確に一度だけ実行されます。 回実行されます。
  4. すべてのシャードが終了するのを待って、結果を収集し、報告する。

あなたのプロジェクトには GoogleTest を使わずに書かれたテストがあるかもしれないので、 その場合はこのプロトコルを理解できません。 はこのプロトコルを理解していません。テストランナーがどのテストがシャーディングをサポートしているかを知るには、 環境変数 がシャーディングをサポートしているかどうかを調べるには、 環境変数 GTEST_SHARD_STATUS_FILE に存在しないファイルパスを指定します。 を存在しないファイルパスに設定します。もしテストプログラムがシャーディングをサポートしていれば、その事実を認識するためにこのファイルを作成します。 そうでない場合は作成されません。実際の このファイルの実際の内容は、現時点では重要ではありません。 将来的には有用な情報を入れるかもしれません。

ここで、分かりやすくするために例を挙げます。テストプログラム foo_test があるとします。 というテストプログラムがあり、以下の 5 つのテスト関数が含まれているとします。

TEST(A, V)
TEST(A, W)
TEST(B, X)
TEST(B, Y)
TEST(B, Z)

自由に使えるマシンが3台あるとします。テスト関数を並列に実行するために テスト関数を並列に実行するには、すべてのマシンで GTEST_TOTAL_SHARDS を 3 に設定し、それぞれ GTEST_SHARD_INDEXをそれぞれ 0, 1, 2 に設定します。そして 各マシンで同じfoo_test` を実行します。

GoogleTestは、シャード間の作業の分配方法を変更する権利を有します。 シャードへの作業の分配方法を変更する権利を有しますが、ここでは可能なシナリオの1つを紹介します。

  • マシン#0 は A.VB.X を実行します。
  • マシン#1 は A.WB.Y を実行します。
  • マシン#2 は B.Z を実行します。

テスト出力の制御

カラー端子出力

googletest はターミナル出力に色を使って、重要な情報を見つけやすくすることができます。 重要な情報を見つけやすくします。

...
[----------] 1 test from FooTest
[ RUN ] FooTest.DoesAbc
[       OK ] FooTest.DoesAbc
[----------] 2 tests from BarTest
[ RUN      ] BarTest.HasXyzProperty
[       OK ] BarTest.HasXyzProperty
[ RUN ] BarTest.ReturnsTrueOnSuccess
...いくつかのエラーメッセージ...
[   FAILED ] BarTest.ReturnsTrueOnSuccess
...
[==========] 30 tests from 14 test suites ran.
[   PASSED ] 28 tests.
[   FAILED ] 2 tests, listed below:
[   FAILED ] BarTest.ReturnsTrueOnSuccess
[ FAILED ] AnotherTest.DoesXyz

 2 FAILED TESTS

環境変数 GTEST_COLOR やコマンドラインフラグ --gtest_color を設定することで、色を有効にすることができます。 コマンドラインフラグを yesno または auto (デフォルト) に設定すると、色を有効にすることができます。 色を有効にするか、無効にするか、googletest に決定させるかを指定します。この値が auto である場合、 googletest は以下の場合にのみ色を使用します。 はターミナルに出力される場合のみ色を使用し、(Windows 以外のプラットフォームでは) TERM 環境を使用します。 プラットフォームで) TERM 環境変数が xterm または xterm-color に設定されている場合にのみ、googletest は色を使用します。

テストパスの抑制

デフォルトでは、googletest は各テストに対して 1 行の出力を行い、それが合格か不合格かを示します。 を表示します。失敗したテストだけを表示するには、テストプログラムを として実行するか、環境変数 GTEST_BRIEF を 1 に設定します。

経過時間の抑制

デフォルトでは、googletest は各テストを実行するのにかかる時間を表示します。これを無効にするには コマンドラインフラグ --gtest_print_time=0 を指定してテストプログラムを実行するか、環境変数 GTEST_PRINT_TIME を 0 に設定してください。 GTEST_PRINT_TIME 環境変数を 0 に設定します。

UTF-8テキスト出力の抑止

アサーションに失敗した場合、googletest は string 型の期待値と実際の値を表示します。 タイプ string の期待値と実際の値を 16 進数で表示します。 UTF-8 の文字が含まれている場合は、UTF-8 で表示します。もし、UTF-8テキストを表示しないようにしたいならば、例えば、あなたがUTF-8テキストを表示しないようにすることができます。 テキストを抑制したい場合、例えば、UTF-8互換の出力媒体を持っていない場合などには を指定してテストプログラムを実行するか、環境変数 GTEST_PRINT_UTF80 にセットしてください。 環境変数を 0 に設定してください。

XMLレポートの作成

googletest は通常のテキスト出力に加え、詳細な XML レポートをファイルに出力することができます。 を出力します。このレポートにはそれぞれのテストの所要時間が含まれているので このレポートには各テストの時間が含まれているので、遅いテストを特定するのに役立ちます。

XMLレポートを生成するには、環境変数 GTEST_OUTPUT または --gtest_output フラグに文字列 "xml:path_to_output_file" を設定します。 gtest_outputフラグに"xml:path_to_output_file"という文字列を設定します。 この場合、指定された場所にファイルが作成されます。また、単に文字列"xml"を使用することもできます。 この場合、出力はカレントディレクトリにあるtest_detail.xml` ファイルになります。 ファイルに出力されます。

ディレクトリを指定した場合 (例えば Linux では "xml:output/directory/" 、Windows では "xml:output</directory") 、googletest はそのディレクトリに XML ファイルを作成します。 Windows では "xml:outputdirectory") を指定すると、googletest はそのディレクトリに XML ファイルを作成します。 そのディレクトリにテスト実行ファイルにちなんだ名前の XML ファイルが作成されます (例: foo_test がテストプログラムの場合、foo_test.xml となります)。 という名前の XML ファイルを作成します (例: foo_test または foo_test.exe)。ファイルがすでに存在する場合(おそらく以前の実行から残っている ファイルがすでに存在する場合 (以前の実行時に残っている可能性があります)、googletest は別の名前を選びます (例. 例えば foo_test_1.xml) を選んで、上書きを防ぎます。

このレポートは junitreport というAntタスクがベースになっています。このフォーマットは この形式はもともと Java 用のものなので、googletest のテストに適用するためには少し解釈が必要です。 を googletest のテストに適用するためには、ここで示すようなちょっとした解釈が必要です。

<testsuites name="AllTests" ...>
  <testsuite name="test_case_name" ...>
    <testcase    name="test_name" ...>
      <failure message="..."/>
      <failure message="..."/>
      <failure message="..."/>
    </testcase>
  </testsuite>
</testsuites>
  • ルートである <testsuites> 要素は、テストプログラム全体に対応します。
  • <testsuite> 要素は googletest のテストスイートに対応します。
  • <testcase> 要素は googletest のテスト関数に対応します。

例えば、次のようなプログラムです。

TEST(MathTest, Addition) { ... }
TEST(MathTest, Subtraction) { ... }
TEST(LogicTest, NonContradiction) { ... }

は、このレポートを生成することができました。

<?xml version="1.0" encoding="UTF-8"?>
<testsuites tests="3" failures="1" errors="0" time="0.035" timestamp="2011-10-31T18:52:42" name="AllTests">
  <testsuite name="MathTest" tests="2" failures="1" errors="0" time="0.015">
    <testcase name="Addition" file="test.cpp" line="1" status="run" time="0.007" classname="">
      <failure message="Value of: add(1, 1)&#x0A;  Actual: 3&#x0A;Expected: 2" type="">...</failure>
      <failure message="Value of: add(1, -1)&#x0A;  Actual: 1&#x0A;Expected: 0" type="">...</failure>
    </testcase>
    <testcase name="Subtraction" file="test.cpp" line="2" status="run" time="0.005" classname="">
    </testcase>
  </testsuite>
  <testsuite name="LogicTest" tests="1" failures="0" errors="0" time="0.005">
    <testcase name="NonContradiction" file="test.cpp" line="3" status="run" time="0.005" classname="">
    </testcase>
  </testsuite>
</testsuites>

注意すべき点

  • <testsuites> または <testsuite> 要素の tests 属性は、googletest プログラムまたはテストスイートに含まれるテスト関数の数を表します。 の属性は、googletest プログラムやテストスイートがいくつのテスト関数を含んでいるのかを示します。 failures` 属性はそのうちのいくつが失敗したかを表します。

  • time` 属性は、テスト、テストスイート、またはテストプログラム全体の継続時間を秒単位で表します。 の持続時間を秒単位で表します。

  • timestamp 属性は、テスト実行時のローカルな日時を記録します。 を実行した日時を記録します。

  • fileline` 属性は、テストが定義されたソースファイルの場所を記録します。 テストが定義されたソースファイルの場所を記録します。

  • <failure> 要素は、失敗した googletest のアサーション 1 つに対応します。 のアサーションに対応します。

JSONレポートの生成

googletest は XML の代替フォーマットとして JSON レポートを生成することもできます。JSON レポートを生成するには JSON レポートを生成するには、環境変数 GTEST_OUTPUT または --gtest_output フラグを設定します。 gtest_outputフラグに"json:path_to_output_file"という文字列を設定します。 この場合、指定された場所にファイルが作成されます。また、単に文字列 この場合、出力はカレントディレクトリのtest_detail.json` ファイルに格納されます。 に出力されます。

レポートのフォーマットは、以下のJSON Schemaに準拠しています。

{
  "$schema": "http://json-schema.org/schema#",
  "type": "object",
  "definitions": {
    "TestCase": {
      "type": "object",
      "properties": {
        "name": { "type": "string" },
        "tests": { "type": "integer" },
        "failures": { "type": "integer" },
        "disabled": { "type": "integer" },
        "time": { "type": "string" },
        "testsuite": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/TestInfo"
          }
        }
      }
    },
    "TestInfo": {
      "type": "object",
      "properties": {
        "name": { "type": "string" },
        "file": { "type": "string" },
        "line": { "type": "integer" },
        "status": {
          "type": "string",
          "enum": ["RUN", "NOTRUN"]
        },
        "time": { "type": "string" },
        "classname": { "type": "string" },
        "failures": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/Failure"
          }
        }
      }
    },
    "Failure": {
      "type": "object",
      "properties": {
        "failures": { "type": "string" },
        "type": { "type": "string" }
      }
    }
  },
  "properties": {
    "tests": { "type": "integer" },
    "failures": { "type": "integer" },
    "disabled": { "type": "integer" },
    "errors": { "type": "integer" },
    "timestamp": {
      "type": "string",
      "format": "date-time"
    },
    "time": { "type": "string" },
    "name": { "type": "string" },
    "testsuites": {
      "type": "array",
      "items": {
        "$ref": "#/definitions/TestCase"
      }
    }
  }
}

を使用して、以下の Proto3 に準拠した形式で報告します。 JSONエンコーディングを使用しています。

syntax = "proto3";

package googletest;

import "google/protobuf/timestamp.proto";
import "google/protobuf/duration.proto";

message UnitTest {
  int32 tests = 1;
  int32 failures = 2;
  int32 disabled = 3;
  int32 errors = 4;
  google.protobuf.Timestamp timestamp = 5;
  google.protobuf.Duration time = 6;
  string name = 7;
  repeated TestCase testsuites = 8;
}

message TestCase {
  string name = 1;
  int32 tests = 2;
  int32 failures = 3;
  int32 disabled = 4;
  int32 errors = 5;
  google.protobuf.Duration time = 6;
  repeated TestInfo testsuite = 7;
}

message TestInfo {
  string name = 1;
  string file = 6;
  int32 line = 7;
  enum Status {
    RUN = 0;
    NOTRUN = 1;
  }
  Status status = 2;
  google.protobuf.Duration time = 3;
  string classname = 4;
  message Failure {
    string failures = 1;
    string type = 2;
  }
  repeated Failure failures = 5;
}

例えば、次のようなプログラムです。

TEST(MathTest, Addition) { ... }
TEST(MathTest, Subtraction) { ... }
TEST(LogicTest, NonContradiction) { ... }

は、このレポートを生成することができました。

{
  "tests": 3,
  "failures": 1,
  "errors": 0,
  "time": "0.035s",
  "timestamp": "2011-10-31T18:52:42Z",
  "name": "AllTests",
  "testsuites": [
    {
      "name": "MathTest",
      "tests": 2,
      "failures": 1,
      "errors": 0,
      "time": "0.015s",
      "testsuite": [
        {
          "name": "Addition",
          "file": "test.cpp",
          "line": 1,
          "status": "RUN",
          "time": "0.007s",
          "classname": "",
          "failures": [
            {
              "message": "Value of: add(1, 1)\n  Actual: 3\nExpected: 2",
              "type": ""
            },
            {
              "message": "Value of: add(1, -1)\n  Actual: 1\nExpected: 0",
              "type": ""
            }
          ]
        },
        {
          "name": "Subtraction",
          "file": "test.cpp",
          "line": 2,
          "status": "RUN",
          "time": "0.005s",
          "classname": ""
        }
      ]
    },
    {
      "name": "LogicTest",
      "tests": 1,
      "failures": 0,
      "errors": 0,
      "time": "0.005s",
      "testsuite": [
        {
          "name": "NonContradiction",
          "file": "test.cpp",
          "line": 3,
          "status": "RUN",
          "time": "0.005s",
          "classname": ""
        }
      ]
    }
  ]
}

{: .callout .important} 重要:JSONドキュメントの正確なフォーマットは変更される可能性があります。

不具合の報告方法の管理

テストの早期終了の検出

Google Test はテストランナーのために premature-exit-file プロトコルを実装しています。 を実装しています。開始時に、Google Test はこのファイルを作成し、すべての作業が終了した時点で自動的に削除します。 ファイルを作成します。そして、テストランナーはこのファイルが存在するかどうかをチェックします。ファイルが削除されない場合 が削除されないままだと、テストが途中で終了してしまいます。

この機能は、環境変数 TEST_PREMATURE_EXIT_FILE が設定されている場合のみ有効です。 変数が設定されている場合のみ有効です。

アサーションの失敗をブレークポイントに変える」###アサーションの失敗をブレークポイントに変える

デバッガでテストプログラムを実行するとき、アサーションに失敗したときに デバッガでテストプログラムを実行する場合、 アサーションに失敗したときに自動的に対話型モードに移行できれば非常に便利です。 googletest の break-on-failure モードはこの挙動をサポートしています。

これを有効にするには、環境変数 GTEST_BREAK_ON_FAILURE0 以外の値を設定します。 を 0 以外の値に設定してください。あるいは、--gtest_break_on_failure コマンドラインフラグを使用することもできます。 コマンドラインフラグを使うこともできます。

テストスローの例外をキャッチできないようにする

googletest は例外処理を有効にして使うことも、無効にすることもできます。もしテストが が C++ 例外もしくは (Windows の) 構造化例外 (SEH) をスローする場合、デフォルトでは googletest はそれをキャッチし、テストの失敗として報告し、次のテストメソッドを続けます。 次のテストメソッドに進みます。これはテスト実行のカバレッジを最大化します。また、Windowsでは キャッチされない例外はポップアップウィンドウを引き起こすので、例外をキャッチすることでテストを自動的に実行することができます。 をキャッチすることで、自動的にテストを実行することができます。

しかし、テストの失敗をデバッグするとき、代わりに例外をデバッガで処理したい場合があります。 をデバッガで処理し、例外が発生したときにコールスタックを調べられるようにしたい場合があります。 例外が発生したときのコールスタックを調べることができます。そのためには、 GTEST_CATCH_EXCEPTIONS 環境変数を 0 に設定します。 環境変数を 0 に設定するか、あるいはテストを実行する際に --gtest_catch_exceptions=0 フラグを指定してください。 フラグを使用してください。

サニタリー統合

その 未定義動作サニタイザーアドレスサニタイザー。 および スレッドサニタイザー はすべて、明示的な失敗をトリガーするためにオーバーライドできる弱い関数を提供します。 のようなサニタイザーエラーを検出したときに、明示的な失敗を引き起こすためにオーバーライドできる弱い関数を提供しています。 これらの関数をオーバーライドするには、メイン・ファイルの一部としてコンパイルしたソース・ファイルに関数の定義を記述します。 メイン・バイナリの一部としてコンパイルします。

extern "C" {
void __ubsan_on_report() {
  FAIL() << "Encountered an undefined behavior sanitizer error";
}
void __asan_on_error() {
  FAIL() << "Encountered an address sanitizer error";
}
void __tsan_on_report() {
  FAIL() << "Encountered a thread sanitizer error";
}
}  // extern "C"

サニタイザーを有効にしてプロジェクトをコンパイルした後、もし特定の テストがサニタイザーエラーを引き起こした場合、googletest はそれが失敗したと報告します。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment