上級ガイド

Google C++ Testing Framework を利用した高度なトピック

さて,あなたは 入門ガイド を読み終え,Google Test を使ったテストの書き方が分かったことでしょう.ここでは,今までとは別のアサーション,複雑な失敗メッセージの作成方法,致命的な失敗の伝播方法,テストフィクスチャの再利用と高速化手法,そして,テストで用いる様々なフラグの利用法について解説します.

その他のアサーション

ここでは,利用頻度は低いですが重要なアサーションを紹介します.

明示的な成功と失敗

これら3つのアサーションは,実際には値や式のテストを行いません.その代り,成功や失敗を直接生成します.実際にテストを行うマクロと同じように,これらのアサーションでもユーザ定義の失敗メッセージを利用できます.

 
SUCCEED();

成功を生成します.しかし,これはテスト全体を成功させるものでは ありません .テスト実行時に,そこに含まれるすべてのアサーションが失敗しなかった場合にのみ,そのテスト全体が成功したとみなされます.

注意 :SUCCEED() は,書くことができるだけで,ユーザに見える形での出力は一切行いません.しかし,将来的には Google Test の出力に SUCCEED() メッセージを追加する予定です.

     
FAIL(); ADD_FAILURE(); ADD_FAILURE_AT(“file_path”, line_number);

FAIL() は,致命的な失敗を生成します.一方,ADD_FAILURE() と ADD_FAILURE_AT() は,致命的ではない失敗を生成します.これらは,テストが成功か失敗かを決めるのに,ブール式ではなくプログラムの制御フローを用いる場合に役立ちます. 例えば,次のような書き方をしたい場合があるでしょう:

switch(expression) {
  case 1: ... some checks ...
  case 2: ... some other checks
  ...
  default: FAIL() << "We shouldn't get here."; // ここに来てはダメ.
}

利用可能な環境: Linux,Windows,Mac.

例外アサーション

これらは,あるコードが,決められた型の例外を投げる(または,投げない)かを検証します.

致命的なアサーション 致命的ではないアサーション 検証内容
ASSERT_THROW(statement, exception_type); EXPECT_THROW(statement, exception_type); statement が与えられた型の例外を投げる
ASSERT_ANY_THROW(statement); EXPECT_ANY_THROW(statement); statement が任意の型の例外を投げる
ASSERT_NO_THROW(statement); EXPECT_NO_THROW(statement); statement が例外を投げない

例:

 ASSERT_THROW(Foo(5), bar_exception);

EXPECT_NO_THROW({
   int n = 5;
   Bar(&n);
 });

利用可能な環境: Linux,Windows,Mac.ただし,バージョン 1.1.0以降.

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

Google Test は現在も豊富なアサーションを提供していますが,これが完璧になることはありません.ユーザが遭遇する可能性のある全てのシナリオに備えておくことは不可能ですし,仮にできたとしても,良い考えとは言えません.そのため,このマクロを補うために,ユーザが EXPECT_TRUE() を使って複雑な式を検証しなければならないこともあるでしょう.これには,式の一部の値を見ることができないという問題があり,このせいで問題箇所を特定するのが難しくなります.回避策として,ユーザ自身が失敗メッセージを作り,それを EXPECT_TRUE() の引数に使う,という方法があります.しかし,式に副作用があったり,式の評価が重い処理だった場合,この方法は特に問題になります.

Google Test には,この問題を解決する3つの選択肢があります:

既存のブール関数を利用する

bool値(または暗黙の型変換でbool値にできる型)を返す関数またはファンクタが既にある場合,それを述語アサーションに与えるだけで,関数の引数を表示できます.

致命的なアサーション 致命的ではないアサーション 検証内容
ASSERT_PRED1(pred1, val1); EXPECT_PRED1(pred1, val1); pred1(val1) が true を返す
ASSERT_PRED2(pred2, val1, val2); EXPECT_PRED2(pred2, val1, val2); pred2(val1, val2) が true を返す
... ... ...

上述の predn は n 個の引数を取る述語関数またはファンクタで,val1, val2, ..., valn が引数を表します.指定した引数を与えられた述語(関数)が true の場合,アサーションは成功します.そうでない場合は失敗します.アサーションが失敗すると,引数が表示されます.いずれの場合も,引数は1度だけ評価されます.

例を示します.例えば,以下が与えられたとしましょう.

// m と n が互いに素な場合のみ true を返します
bool MutuallyPrime(int m, int n) { ... }
const int a = 3;
const int b = 4;
const int c = 10;

アサーション EXPECT_PRED2(MutuallyPrime, a, b); は成功しますが,EXPECT_PRED2(MutuallyPrime, b, c); は失敗して次のようなメッセージを出力します.

MutuallyPrime(b, c) is false, where
b is 4
c is 10

注意

  1. ASSERT_PRED* または EXPECT_PRED* を利用した際に “no matching function to call” というコンパイルエラーがでる問題を解決するには, よくある質問 を参照してください.
  2. 現在用意されているのは,引数 5 個以下の述語アサーションのみです.さらに多くの引数を取る必要があれば,我々に知らせてください.

利用可能な環境: Linux,Windows,Mac.

AssertionResult を返す関数を利用する

上で紹介した EXPECT_PRED*() とその仲間は,ちょっとした仕事をする際に役立ちます.ただし,構文が十分とは言えないので,引数の数が異なる場合は別のマクロを使う必要があります.これは C++ というよりも Lisp に近いかもしれません.::testing::AssertionResult クラスを使えば,この問題を解決できます.

AssertionResultオブジェクトは,アサーションの結果(成功したか失敗したか,および関連メッセージ)を表します. 次のファクトリ関数のいずれかを使って,AssertionResult を作成できます.

 namespace testing {

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

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

 }

そして,<< 演算子を使って AssertionResult オブジェクトにメッセージを追加できます.

Boolean アサーション(EXPECT_TRUE())で,もっと読みやすいメッセージを出力するためには,bool の代わりに 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;
}

EXPECT_TRUE(IsEven(Fib(4))) は失敗するアサーションで,次のような出力を行います.

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

AssertionResult を使わないと,少し説明不足な出力となります.

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

EXPECT_FALSE や ASSERT_FALSE でも同様の分かりやすいメッセージを使いたいならば,(失敗メッセージではなく)成功メッセージを出力することもできます.ただし,成功する場合にも述語関数を作るので,多少処理が遅くなっても問題ない場合に使ってください:

この場合 EXPECT_FALSE(IsEven(Fib(6))) は,次のような出力を行います.

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

利用可能な環境: Linux,Windows,Mac.ただし,バージョン 1.4.1以降.

述語フォーマッタを利用する

(ASSERT|EXPECT)_PRED* や (ASSERT|EXPECT)_(TRUE|FALSE) が生成するデフォルトメッセージが不十分な場合や,述語関数の引数がストリーム ostream への出力をサポートしていない場合,代わりに次の述語フォーマッタアサーションを利用することができます:

致命的なアサーション 致命的ではないアサーション 検証内容
ASSERT_PRED_FORMAT1(pred_format1, val1); EXPECT_PRED_FORMAT1(pred_format1, val1); pred_format1(val1) が成功する
ASSERT_PRED_FORMAT2(pred_format2, val1, val2); EXPECT_PRED_FORMAT2(pred_format2, val1, val2); pred_format2(val1, val2) が成功する
... ... ...

これが以前の2種類のマクロと異なる点は,(ASSERT|EXPECT)_PRED_FORMAT* は述語関数の代わりに述語フォーマッタ(pred_formatn)を受け取る,という事です.これは,次のような形式の関数またはファンクタです:

::testing::AssertionResult PredicateFormattern(const char* expr1, const char* expr2, ... const char* exprn, T1 val1, T2 val2, ... Tn valn);

val1, val2, ..., valn は引数の値です. expr1, expr2, ..., exprn はその引数に対応した式や変数の名前で,これはソースコード中に書かれているものです.型 T1, T2, ..., Tn は値型でも参照型でも構いません.例えば,引数の型が Foo だとすると,これを Foo または const Foo& のどちらで宣言しても構いません.どちらでも,適切です.

述語フォーマッタは,アサーションが成功したが失敗したかを示すオブジェクト::testing::AssertionResult を返します. このようなオブジェクトを作成する唯一の方法は,これらのファクトリ関数を使うことです:

例として,以前の EXPECT_PRED2() の説明で出てきた失敗メッセージを改良してみましょう:

// m と n の公約数のうち,最小の素数を返します.
// また,m と n が互いに素の場合は 1 を返します.
int SmallestPrimeCommonDivisor(int m, int n) { ... }

// 2つの整数が互いに素かを調べるアサーション用の述語フォーマッタ.
::testing::AssertionResult AssertMutuallyPrime(const char* m_expr,
                                               const char* n_expr,
                                               int m,
                                               int n) {
  if (MutuallyPrime(m, n))
    return ::testing::AssertionSuccess();

  return ::testing::AssertionFailure()
      << m_expr << " and " << n_expr << " (" << m << " and " << n
      << ") are not mutually prime, " << "as they have a common divisor "
      << SmallestPrimeCommonDivisor(m, n);
}

この述語フォーマッタを用いて,次のように書くことができます.

EXPECT_PRED_FORMAT2(AssertMutuallyPrime, b, c);

これは,以下のメッセージを出力します.

b and c (4 and 10) are not mutually prime, as they have a common divisor 2.

既に気づいているかもしれませんが,以前に紹介したアサーションの多くは,(EXPECT|ASSERT)_PRED_FORMAT* の特別な場合です.実際,それらは (EXPECT|ASSERT)_PRED_FORMAT* を用いて定義されています.

利用可能な環境: Linux,Windows,Mac.

浮動小数点数の比較

浮動小数点数の比較は,微妙な問題です.丸め誤差があるので,2つの浮動小数点数が完全に一致することは非常にまれです.よって,ASSERT_EQ での比較は上手くいきません.また,浮動小数点数の値のとる範囲は広いので,ある固定の誤差範囲を使っても上手くいきません. 相対誤差範囲で比較するのは,それよりは良い方法ですが,0 に近い値は精度が低いのでやはり上手くいきません.

一般的に,浮動小数点数の比較を上手く行うには,ユーザが慎重に誤差範囲を指定する必要があります.そのような手間をかけたくない場合,最下位桁単位(Units in the Last Place: ULPs)を使って比較するのは良い方法と言えますし,Google Test のアサーションでもそうしています.ULPs について詳しく述べると,非常に長くなります.詳細については, 浮動小数点数の比較に関するこの記事 を読んでください.

浮動小数点マクロ

致命的なアサーション 致命的ではないアサーション 検証内容
ASSERT_FLOAT_EQ(expected, actual); EXPECT_FLOAT_EQ(expected, actual); 2つの float 値が,ほぼ等しい
ASSERT_DOUBLE_EQ(expected, actual); EXPECT_DOUBLE_EQ(expected, actual); 2つの double 値が,ほぼ等しい

ここでの「ほぼ等しい」とは,2つの値の差が 4 ULPs 以内になることを意味しています.

次のアサーションを使うと,許容誤差範囲を指定することができます.

致命的なアサーション 致命的ではないアサーション 検証内容
ASSERT_NEAR(val1, val2, abs_error); EXPECT_NEAR(val1, val2, abs_error); val1 と val2 の差が,与えられた絶対誤差以内に収まる

利用可能な環境: Linux,Windows,Mac.

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

便利ではあるものの使用頻度は低い,という浮動小数点処理が存在します.これらに対して新しいマクロが爆発的に増えないように,述語アサーションマクロ(例えば,EXPECT_PRED_FORMAT2 など)で利用できる述語フォーマット関数が用意されています.

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

これは,val1 が val2 以下であることをテストします. EXPECT_PRED_FORMAT2 を ASSERT_PRED_FORMAT2 に変更することもできます.

利用可能な環境: Linux,Windows,Mac.

Windows HRESULT アサーション

これらのアサーションは,HRESULT が成功か失敗かをテストします.

致命的なアサーション 致命的ではないアサーション 検証内容
ASSERT_HRESULT_SUCCEEDED(expression); EXPECT_HRESULT_SUCCEEDED(expression); expression が success HRESULT
ASSERT_HRESULT_FAILED(expression); EXPECT_HRESULT_FAILED(expression); expression が failure HRESULT

ここで生成される出力には,人間が読めるエラーメッセージが含まれています.これは,expression が返す HRESULT コードに関連するものです.

例えば,次のようにして利用できます:

CComPtr shell;
ASSERT_HRESULT_SUCCEEDED(shell.CoCreateInstance(L"Shell.Application"));
CComVariant empty;
ASSERT_HRESULT_SUCCEEDED(shell->ShellExecute(CComBSTR(url), empty, empty, empty, empty));

利用可能な環境: Windows.

型アサーション

この関数の呼び出し方は次のようになります.

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

これは,T1 と T2 の型が同じであることをアサートします.型が等しくアサーションが成功する場合は,この関数は何もしません.型が異なる場合は,この関数呼び出しはコンパイルに失敗します.おそらく(コンパイラに依存しますが),コンパイルエラーメッセージで T1 と T2 の実際の値が表示されるでしょう.これは,主にテンプレートコード内で利用されるものです.

注意: クラステンプレートのメンバ関数内,または関数テンプレート内で利用する場合,StaticAssertTypeEq<T1, T2>() は,その関数がインスタンス化されて始めて効果があります.例えば,次のようなクラステンプレートが定義されたとします:

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

そして,実際のコードが次のようになっているとします:

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

ここで,Foo<bool>::Bar() は実際にはインスタンス化されないので,このコードはコンパイルエラーを起こしません.代わりに

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

というコードは,正しくコンパイルエラーを発生させます.

利用可能な環境: Linux,Windows,Mac.バージョン 1.3.0 以降.

アサーションの配置

アサーションは,任意の C++ 関数で利用できます.特に,テストフィクスチャクラスのメソッドにする必要はありません.ただし,致命的な失敗を発生させるアサーション(FAIL* と ASSERT_*)は,void を返す関数内でのみ利用できるという制約があります.これは,Google Test が例外を利用していないことが原因です.もし void 関数以外で利用しようとすると, “error: void value not ignored as it ought to be” というようなコンパイルエラーに悩まされることになるでしょう.

もし,void 以外を返す関数でアサーションを利用したい場合の選択肢の1つは,戻り値の代わりに引数で値を返す関数に変更する,というものです.例えば,T2 Foo(T1 x) を void Foo(T1 x, T2* result) に変更します.ただし,この関数が最後まで実行されずに返ったとしても,*result に意味のある値が入るようにする必要があります.この関数は void を返すので,関数内で自由にアサーションを使うことができます.

関数の型を変更する方法が使えなければ,ADD_FAILURE* や EXPECT_* のような,致命的ではない失敗を発生するアサーションを利用するしかないでしょう.

注意 : C++ の仕様によれば,コンストラクタとデストラクタは,voidを返す関数とはみなされません.よって,その中で致命的な失敗を発生させるアサーションを使うことはできません.もし使おうとすれば,コンパイルエラーになります.単純な回避策としては,コンストラクタとデストラクタの中身全体を void を返す private なメソッドに移してしまうことです.しかし,直感的に分かるかもしれませんが,コンストラクタ内の致命的なアサーションは現在のテストを終了させないことに注意してください.これは,部分的に作成されたオブジェクトをそのままにして,単にコンストラクタから早く返るだけです.同じように,デストラクタ内のアサーションの致命的失敗も,オブジェクトを部分的に破棄した状態にします.このような状況では,注意してアサーションを利用してください.

Google Test に値の表示方法を教示する

EXPECT_EQ のようなテストアサーションが失敗すると,Google Test は,デバッグしやすいように引数の値を表示します.この表示は,ユーザが拡張可能な値プリンタを利用して行われます.

このプリンタは,C++ の組み込み型,ネイティブな配列,STL コンテナ,<< 演算子をサポートする任意の型を出力することができます.しかし,その他の型の場合は,生のバイト値を表示して,ユーザがそれの意味を分かってくれることを願うのみです.

前述したように,このプリンタは拡張可能です.これは,ある特定の型を出力する際には,バイト値をダンプするより良い方法を教示することができる,ということを意味します.そのためには,その型に対して << 演算子を定義します:

#include <iostream>

namespace foo {

class Bar { ... };  // Google Test が,これのインスタンスを出力できるようになってほしい.

// Bar の定義と「同じ」名前空間で << 演算子を定義することが重要です.
// C++ のルックアップルールは,それに依存しています.
::std::ostream& operator<<(::std::ostream& os, const Bar& bar) {
  return os << bar.DebugString();  // bar を os に出力するのに必要な処理を書きます
}

}  // 名前空間 foo

この選択肢をとれない場合があるかもしれません:あなたのチームが,Bar に対して << 演算子を定義するのは悪いスタイルであると見なしている場合,Bar に対して既に << 演算子が定義されていて,その動作が望むものではない(そして,その変更もできない)場合,などです.その場合,代わりに PrintTo() 関数を次のように定義することができます:

#include <iostream>

namespace foo {

class Bar { ... };

// Bar の定義と「同じ」名前空間で PrintTo() を定義することが重要です.
// C++ のルックアップルールは,それに依存しています.
void PrintTo(const Bar& bar, ::std::ostream* os) {
  *os << bar.DebugString();  // bar を os に出力するのに必要な処理を書きます
}

}  // 名前空間 foo

<< と PrintTo() の両方が定義されている場合,Google Test は後者を利用します.このおかげで,自身の << 演算子の動作に依存するコードに影響を与えることなく,Google Test の出力に値を表示する方法をカスタマイズできます.

Google Test の値プリンタを用いて,x の値を自分で出力したいならば, std::string を返す ::testing::PrintToString(x) を呼び出すだけです:

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

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

Death テスト

多くのアプリケーションにおいて,条件が満たされない場合にアプリケーションを落としてしまうアサーションが存在します.これらのチェックは,プログラムが正常な状態にあることを保障し,プログラムが異常状態になった場合にできるだけ迅速に失敗させるためにあります.アサーションがチェックする条件が間違っていると,誤った状態で処理が進み,メモリ破壊やセキュリティホール,それ以上の障害の原因になる可能性があります.よって,このようなアサーションが期待通りに動作することをテストするのは,極めて重要といえます.

これらの前提条件チェックはプロセスを殺してしまうので,このようなテストを Death テスト と呼びます.より一般的には,プログラムが期待通りの方法で終了すること(ただし例外によるものを除く)をチェックするテスト全般を Death テストと呼びます.

あるコードの一部が例外を投げる場合,それは Death テストが対象とする「Death」とは見なされないので,そのコード部分を呼び出した側が,その例外をキャッチしてクラッシュを避けることができます.あなたのコードが例外を投げらていることを検証したい場合は, 例外アサーション の項を参照してください.

また,テストコード中の EXPECT_*()/ASSERT_*() の失敗をテストしたいならば, 失敗をキャッチする の項を参照してください.

Deathテストの書き方

Google Test では,Death テストをサポートする次のマクロが用意されています:

致命的なアサーション 致命的ではないアサーション 検証内容
ASSERT_DEATH(statement, regex); EXPECT_DEATH(statement, regex); 与えられたエラーが発生し,statement がクラッシュ
ASSERT_DEATH_IF_SUPPORTED(statement, regex); EXPECT_DEATH_IF_SUPPORTED(statement, regex); Death テストがサポートされていれば,statement が与えられたエラーでクラッシュすることを検証し,そうでなければ何もしない
ASSERT_EXIT(statement, predicate, regex); EXPECT_EXIT(statement, predicate, regex); statement が与えられたエラーで終了し,終了コードが predicate にマッチする

ここで,statement は,プロセスを殺すであろう文,predicate は,終了ステータスを評価する関数またはファンクタ, regex は,statement の標準出力とマッチする正規表現,をそれぞれ意味します.statement は1つの式である必要はなく,(複合的な命令文も含む)あらゆる有効な命令文を指定することができます.

通常,ASSERT バージョンは現在のテスト関数を終了させますが,EXPECT バージョンは終了させません.

注意 : ここでは,プログラムが 0 以外のステータスコードで終了することを「クラッシュ」と呼んでいます.これには,次の2つの原因が考えられます:プロセスが exit() または _exit() を0ではない引数で呼び出した場合. あるいは,シグナルによって殺された場合,です.

これはつまり,statement が終了コード 0 でプロセスを終了させても,EXPECT_DEATH はクラッシュとは判断しない,という事です.

ここでの述語関数は,必ず int 型を受け取り bool 型を返す必要があります.述語関数が true を返した場合のみ,Death テストが成功します.Google Test では,頻繁に利用される述語関数をいくつか定義しています:

::testing::ExitedWithCode(exit_code)

この式は,プログラムが引数の終了コードで正常終了した場合に true を返します.

::testing::KilledBySignal(signal_number)  // Windowsでは無効.

この式は,プログラムが引数のシグナルに殺された場合に true を返します.

*_DEATH は便利なマクロで,プロセスの終了コードがゼロではないことを検証する述語関数を引数にした場合の *_EXIT をラップしたものです.

Death テストでは,次の3点に注意してください:

  1. statement は,プロセスを強制終了または終了させたか?
  2. (ASSERT_EXIT と EXPECT_EXIT の場合) 終了ステータスは,predicate を満たすか?または(ASSERT_DEATH と EXPECT_DEATH の場合)終了ステータスは 0 以外の値か?
  3. 標準エラー出力は regex とマッチするか?

特に,statement が ASSERT_* または EXPECT_* の失敗を引き起こした場合でも,Google Test のアサーションはプロセスを強制終了させないので,Death テストの失敗とはなりません.

上述のマクロの 1 つをテスト関数の中で使用するだけで,Death テストを書くことができます.次に例を示します:

TEST(My*DeathTest*, Foo) {
  // この Death テストは,複合文を利用します.
  ASSERT_DEATH({ int n = 5; Foo(&n); }, "Error on line .* of Foo()");
}
TEST(MyDeathTest, NormalExit) {
  EXPECT_EXIT(NormalExit(), ::testing::ExitedWithCode(0), "Success");
}
TEST(MyDeathTest, KillMyself) {
  EXPECT_EXIT(KillMyself(), ::testing::KilledBySignal(SIGKILL), "Sending myself unblockable signal");
}

これは,次のことを検証します:

  • Foo(5) がプロセスをクラッシュさせ,与えられたエラーメッセージを出力する.
  • NormalExit() によって,プロセスは標準エラー出力に “Success” を出力し,終了コード 0 で終了する.
  • KillMyself() は,シグナル SIGKILL によってプロセスを殺す.

今までと同様に,必要ならばテスト関数内に他のアサーションや文を含めることができます.

重要 : 上述のサンプルと同じく,Death テストを含むテストケース(テストではありません)を,*DeathTest という名前にする事を強く勧めます.その理由は, Death テストとスレッド のセクションで説明します.

通常のテストとDeath テストとで,テストフィクスチャクラスを共有する場合,typedef でフィクスチャクラスに別名を与え,同じコードが複製されることを防ぎます.

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

typedef FooTest FooDeathTest;

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

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

利用可能な環境: Linux,Windows(MSVC 8.0 以降が必要),Cygwin,Mac.(ただし,後者3つは,バージョン 1.3.0 以降でサポートされます).(ASSERT|EXPECT)_DEATH_IF_SUPPORTED は,バージョン 1.4.0 で導入されました.

正規表現の構文

POSIX システム(例えば,Linux,Cygwin,Macなど)環境において,Google Test の Death テストでは POSIX拡張正規表現 構文を利用しています.この構文について知りたければ, このWikipediaエントリー が参考になるでしょう.

Windows環境での Google Test は,シンプルな正規表現の独自実装を利用しています.しかし,POSIX拡張正規表現と比べると多くの機能が不足しています.例えば,結合(”x|y”),グループ化(”(xy)”),カギ括弧(”[xy]”),繰り返し(”x{5,7}”)などがサポートされていません.サポートされる構文を以下に示します(A は,ある1文字,ピリオド(.)または 1つの \ エスケープシーケンスを表します.また,x と y は通常の正規表現を表します.):

   
c 任意のリテラル文字 c にマッチします
\\d 任意の数字にマッチします
\\D 数字ではない任意の文字にマッチします
\\f \f にマッチします
\\n \n にマッチします
\\r \r にマッチします
\\s \n を含む,任意のASCII空白にマッチします
\\S 空白ではない任意の文字にマッチします
\\t \t にマッチします
\\v \v にマッチします
\\w 任意のアルファベット,アンダースコア,数字にマッチします
\\W \w がマッチしない任意の文字にマッチします
\\c 任意の句読記号にマッチします
. \n ではない任意の1文字にマッチします
A? A の0回または1回の繰り返しにマッチします
A* A の0回以上の繰り返しにマッチします
A+ A の1回以上の繰り返しにマッチします
^ 文字列の先頭にマッチします(行頭ではありません)
$ 文字列の末尾にマッチします(行末ではありません)
xy x とその後ろの y にマッチします

自分のシステムでどちらの正規表現機能を有効にするかを決めるには,Google Test が定義するマクロを利用します.POSIX拡張正規表現を利用する場合は,マクロ GTEST_USES_POSIX_RE=1 ,シンプル版を利用する場合は,マクロ GTEST_USES_SIMPLE_RE=1 を使います.どちらの場合でもDeath テストを動作させたい場合,#if でこれらのマクロを場合分けするか,または,両方でサポートされている限られた構文だけを利用してください.

動作説明

内部的には,ASSERT_EXIT() が新しいプロセスを作り,そのプロセス内でDeathテスト文を実行します.厳密にどのような動作をするかというのは,そのプラットフォームと(コマンドラインフラグ —gtest_death_test_style によって初期化される)変数 ::testing::GTEST_FLAG(death_test_style) に依存します.

  • POSIXシステムでは,子プロセスを作るためにfork()(Linuxでは clone())が利用されます.そして:
    • 変数の値が “fast” の場合,Deathテスト文は即座に実行されます.
    • 変数の値が “threadsafe” の場合,子プロセスがユニットテストバイナリを再実行します.これは,元々と同じように実行されますが,実行待機中のDeathテストを1つだけ起動するためのフラグを追加する点が異なります.
  • Windows では,子プロセスを作るためにCreateProcess() APIが利用されます.そして,実行待機中のDeathテストが1つだけ起動されるように,子プロセスでバイナリが再実行されます.これは,POSIX での threadsafe モードと同じです.

変数にこれ以外の値が入ることは不正であり,その場合 Death テストは失敗します.現在のところ,フラグのデフォルト値は “fast” です.しかし,将来的には変更される可能性があります.よって,これに依存するようなテストを書かないようにしてください.

どちらの場合でも,親プロセスは子プロセスの終了を待ちます.そして,次のチェックを行います

  1. 子プロセスの終了ステータスが,述語関数を満足しているか
  2. 子プロセスの標準エラー出力が,正規表現にマッチしているか

子プロセスが終了したにもかかわらず,Deathテスト文がクラッシュせずに終了した場合,アサーションは失敗します.

Death テストとスレッド

Death テストに2種類のスタイルがある理由は,スレッドセーフな実行のためです.マルチスレッドでプロセスを生成すると,様々な問題を引き起こす可能性があることは広く知られています.そのため,Deathテストはシングルスレッドで実行される必要があります.しかし,そのような環境を用意するのが不可能な場合もあります.例えば,静的に初期化されるモジュールでは,メインスレッドよりも前にスレッドを開始する可能性があります.一度複数のスレッドが作成されると,それらを完全に終了させるのは難しく,場合によっては不可能です.

Google Test には,スレッド問題に対する意識を高めるための3つの機能があります.

  1. Death テスト実行時に複数のスレッド実行されていると,警告が出されます.
  2. “DeathTest” で終わる名前のテストケースは,他の全てのテストよりも前に実行されます.
  3. fork() を使うと,親プロセスがマルチスレッドの場合に,子プロセスをハングアップさせる可能性が高いので,Linux(CygwinやMacではclone() は利用できません)で子プロセスを生成する場合は,fork() の代わりに clone() を利用します.

Death テスト文の中でマルチスレッドを作成するのは全く問題ありません.それらは別々のプロセスで実行され,親プロセスに影響を与えることが不可能だからです.

Death テストのスタイル

“threadsafe” な Death テストスタイルは,マルチスレッドが可能な環境でのテストのリスクを低減するために導入されました.テストの実行時間(非常に遅くなる可能性もあります)とスレッドの安全性はトレードオフの関係にあります.テストに特別な問題がない限り,高速なデフォルトの “fast” スタイルを使うことをお勧めします.

プログラム内でフラグをセットすることで,Death テストのスタイルを選択できます:

::testing::FLAGS_gtest_death_test_style = "threadsafe";

main() でこれを行って,バイナリ内のすべての Death テストのスタイルを決めることもできますし,各テストのスタイルを個々に決めることもできます.フラグは各テストの実行前に保存され,実行後に復元されることを思い出してください.ユーザが復元作業を行う必要はありません.例えば:

 TEST(MyDeathTest, TestOne) {
   ::testing::FLAGS_gtest_death_test_style = "threadsafe";
   // このテストは "threadsafe" スタイルで実行されます:
   ASSERT_DEATH(ThisShouldDie(), "");
 }

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

 int main(int argc, char** argv) {
   ::testing::InitGoogleTest(&argc, argv);
   ::testing::FLAGS_gtest_death_test_style = "fast";
   return RUN_ALL_TESTS();
 }

注意事項

ASSERT_EXIT() の statement 引数には,任意の有効な C++ の文が利用できます.return 文や例外を投げることで現在の関数から抜けた場合,Death テストは失敗したと見なされます.Google Test のマクロが,現在の関数からリターンしてしまう可能性のあるもの(例えば, ASSERT_TRUE() )は,statement に含めないようにしてください.

statement は子プロセスで実行されるので,それが引き起こすメモリに対する副作用(例えば,変数の変更,メモリ解放など)は,親プロセスからは観測できません.具体的に言えば,Death テスト内でメモリを解放すると,親プロセスからは回収されたメモリが見えなくなるので,プログラムはヒープチェックに失敗します. この問題を解決するためにできることは,次の通りです.

  1. Death テスト中はメモリを解放しない
  2. 親プロセス内で再びメモリを解放する
  3. プログラムでヒープチェックを行わない

実装上の問題で,複数の Death テストアサーションを同じ行に書くことはできません.もし書けば,コンパイルが失敗して,不可解なエラーメッセージが出力されます.

Death テストの “threadsafe” スタイルによってスレッド安全性が向上したにもかかわらず,pthread_atfork(3) で登録されたハンドラが存在する場合は,デッドロックなどのスレッド問題は依然として起こりえます.

サブルーチンでのアサーションの利用

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

テストサブルーチンが複数の場所から呼び出されて,その内部のアサーションが失敗したとき,サブルーチンのどの呼び出しに原因があるのか特定が難しくなる場合があります.ロギングを追加したり,独自の失敗メッセージを利用したりして分かりやすくすることもできますが,大抵はテストコードが汚くなります.もっと良い解決法は,SCOPED_TRACE マクロを利用することです.

 
SCOPED_TRACE(message);

ここで,message は,std::ostream に出力可能な任意のメッセージです.このマクロは,現在のファイル名,行数,与えられたメッセージを各失敗メッセージに追加します.この効果は,現在の静的スコープを抜けると解除されます.

以下に例を示します.

void Sub1(int n) {
  EXPECT_EQ(1, Bar(n));
  EXPECT_EQ(2, Bar(n + 1));
}

TEST(FooTest, Bar) {
  {
    SCOPED_TRACE("A");  // このトレースポイントは,スコープ内の
                        // 全ての失敗に追加されます.
    Sub1(1);
  }
  // ここは既に効果範囲外です.
  Sub1(9);
}

この結果,出力されるメッセージは次のようになります:

path/to/foo_test.cc:11: Failure
Value of: Bar(n)
Expected: 1
  Actual: 2
   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() 内の各アサーションに,n の値を表すメッセージを追加することもできますが,面倒な方法です.)

SCOPED_TRACE を使う際のヒント:

  1. 多くの場合,サブルーチンの最初で,適切なメッセージを与えた SCOPED_TRACE を呼び出すだけで充分です.サブルーチンを呼び出す度に使う必要はありません.
  2. ループ内でサブルーチンを呼び出す場合,どのイテレータで失敗したのか分かるように,SCOPED_TRACE のメッセージに,ループイテレータが含まれるようにしてください.
  3. サブルーチンの呼び出し箇所を特定するために,トレースポイントの行番号だけで十分な場合もあります.その場合,SCOPED_TRACE に一意なメッセージを入れる必要はありません.単に,”” と指定することができます.
  4. あるスコープのさらに内側にあるスコープ内で SCOPED_TRACE を使うことができます.その場合,すべての有効なトレースポイントが,発生とは逆の順番で失敗メッセージに含まれます.
  5. トレースダンプは,Emacs のコンパイルバッファ内でクリックすることができます.行番号を選択するとソースファイルの該当行に飛びます.

利用可能な環境: Linux,Windows,Mac.

致命的な失敗の伝播

ASSERT_* や FAIL* を使う際によく陥る間違いは,それが失敗した場合に,テスト全体ではなく 現在の関数 のみを終了させるということを理解していない事によります. 例えば,次のテストはセグメンテーションフォルトを引き起こします.

void Subroutine() {
  // 致命的な失敗を生成し,現在の関数を抜けます.
  ASSERT_EQ(1, 2);
  // これ以降は実行されません.
  ...
}

TEST(FooTest, Bar) {
  Subroutine();
  // Subroutine() 内部で致命的な失敗が起きた時に
  // 期待される挙動は,テスト全体を終了することです.
  // 実際の挙動:Subroutine() から返った後もこの関数は動作し続けます.
  int* p = NULL;
  *p = 3; // セグメンテーションフォルト
}

我々は例外を利用していないので,ここで期待通りの動作を実装するのは技術的に不可能です.これを解決するため,Google Test では2つの方法を用意しています.(ASSERT|EXPECT)_NO_FATAL_FAILURE アサーション,または HasFatalFailure() 関数を利用することができます. これについては,以降の2つのサブセクションで説明します.

サブルーチンでのアサート

以前に説明したように,テストでサブルーチンを呼び出し,そこで ASSERT_* が失敗した場合,サブルーチンから返った後もテストは続行されます.これは,ユーザ望む挙動ではないかもしれません.

致命的な失敗を例外のように伝播したいと考えることがあります.そこで,Google Test では,以下のマクロが用意されています.

致命的なアサーション 致命的ではないアサーション 検証内容
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();
});

利用可能な環境: Linux,Windows,Mac.現在のところ,マルチスレッドでのアサーションはサポートされていません.

現在のテストで失敗のチェック

::testing::Test クラスの HasFatalFailure() は,現在のテスト内のアサーションが致命的な失敗を起こした場合に true を返します.これにより,サブルーチン内の致命的な失敗をキャッチして,より早くリターンすることができます.

典型的な使い方は,例外が投げられ場合と同様で,次のようになります:

TEST(FooTest, Bar) {
  Subroutine();
  // Subroutine() で致命的な失敗が起こると終了.
  if (HasFatalFailure())
    return;
  // これ以降は処理してほしくない.
  ...
}

HasFatalFailure() を TEST(),TEST_F(),またはテストフィクスチャ の外側で使う場合は,必ず次のように,先頭に ::testing::Test を追加してください.

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

同様に,HasNonfatalFailure() は,現在のテストに1つでも致命的ではない失敗が含まれていれば true を返します.そして,HasFailure() は,致命的か致命的でないかに関わらず,現在のテストに1つでもエラーが含まれていれば, true を返します.

利用可能な環境: Linux,Windows,Mac.HasNonfatalFailure() と HasFailure() は,バージョン 1.4.0 以降で利用可能.

その他の情報のロギング

テストコード中に,RecordProperty(“key”, value) 呼び出して追加情報のログを取ることができます.ここで,value は,C文字列または32ビット整数を表します.key に対して記録された最後の値が,例えば,XMLを指定すればその形式で出力されます. 例えば,次のテストを考えましょう.

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

ここで出力されるXMLは,次のようになります:

...
  <testcase name="MinAndMaxWidgets" status="run" time="6" classname="WidgetUsageTest"
            MaximumWidgets="12"
            MinimumWidgets="9" />
...

注意

  • RecordProperty() は,Test クラスの static なメンバです.したがって,Test やテストフィクスチャクラスの外側で利用する場合は,先頭に ::testing::Test:: をつける必要があります.
  • key は,有効な XML 属性名でなければいけません.また,Google Test で利用している名前(name, status, time, classname)と同じものを使うことはできません

利用可能な環境: Linux,Windows,Mac.

同じテストケースに属するテスト間でリソースを共有する

Google Test は,各テストを独立にしてデバッグしやすくするために,,各テスト毎に新しいテストフィクスチャオブジェクトを作成します. しかし,初期化にかかるコストが大きいリソースを使う場合,これを1つのテスト毎にコピーするモデルでは,コストがかかりすぎる場合があります.

テストがリソースを変更しない場合は,1つのリソースコピーを共有しても問題はありません.Google Test では,1つのテスト毎に set-up/tear-down を行う方法に加えて,テストケース毎に set-up/tear-down を行う方法もサポートしています.それを使用するには:

テストフィクスチャクラス(ここでは,FooTest とします)内に,共有リソースを格納する static なメンバ変数を定義します. 同じテストフィクスチャクラス内に,共有リソースを初期化するための static void SetUpTestCase() 関数(SetupTestCase という風に小文字の u と綴らないように注意してください)を定義します. 同じく,共有リソースの終了処理を行う static void TearDownTestCase() を定義します. これだけです.Google Test は,FooTest テストケースの 最初のテスト が実行されるよりも前に(つまり,最初の FooTest オブジェクトが作成されるよりも前に) SetUpTestCase() を自動的に呼び出します.そして,最後のテスト の後で(つまり,最後の FooTest オブジェクトが削除された後で),TearDownTestCase() を呼び出します.この間,テストは共有リソースを利用できます.

テストの順序は未定義なので,前や後で実行されるテストに依存するようなコードを書かないようにしてください.また,テストは共有リソースの状態を変更してはいけません.あるいは,状態を変更した場合は,次のテストに移行する前に必ず元の状態に戻さなければいけません.

ここで,テストケース毎の set-up と tear-down の例を示します:

class FooTest : public ::testing::Test {
 protected:
  // テストケース毎の set-up.
  // このテストケースの最初のテストよりも前に呼び出されます.
  // 必要ならば変更するしてください.
  static void SetUpTestCase() {
    shared_resource_ = new ...;
  }

  // テストケース毎の tear-down.
  // このテストケースの最後のテストの後で呼び出されます.
  // 必要ならば変更するしてください.
  static void TearDownTestCase() {
    delete shared_resource_;
    shared_resource_ = NULL;
  }

  // テスト毎の set-up と tear-down も通常通り定義できます.
  virtual void SetUp() { ... }
  virtual void TearDown() { ... }

  // 高コストのリソースが,全てのテストで共有されます.
  static T* shared_resource_;
};

T* FooTest::shared_resource_ = NULL;

TEST_F(FooTest, Test1) {
  ... ここで,shared_resource を参照できます ...
}
TEST_F(FooTest, Test2) {
   ... ここで,shared_resource を参照できます ...
}

利用可能な環境: Linux,Windows,Mac.

グローバルな Set-Up と Tear-Down

まさに今,テスト単位あるいはテストケース単位で set-up や tear-down を実行したのと同様に,プログラム単位でそれらを実行することができます.ここでは,その方法を説明します.

まず,テスト環境を定義するための ::testing::Environment クラスの派生クラスを作り,そこに set-up と tear-down を定義します:

class Environment {
 public:
  virtual ~Environment() {}
  // 環境の初期化方法を定義するには,これをオーバーライドしてください.
  virtual void SetUp() {}
  // 環境の終了処理を定義するには,これをオーバーライドしてください.
  virtual void TearDown() {}
};

そして, ::testing::AddGlobalTestEnvironment() 関数を使って,Environment クラスのインスタンスを Google Test に登録します.

Environment* AddGlobalTestEnvironment(Environment* env);

RUN_ALL_TESTS() が実行されると,Environment オブジェクトの SetUp() メソッドが最初に呼び出されます.そこで致命的な失敗がなければ,以降のテストが実行され,最後に Environment オブジェクトの TearDown() が呼び出されます.

複数の Environment オブジェクトを登録しても問題ありません.その場合,登録した順番に SetUp() が実行され,その逆の準場で TearDown() が実行されます.

登録された Environment オブジェクトの所有権は Google Test にあることに注意してください.したがって,ユーザはそれらを削除しないでください.

ユーザは,RUN_ALL_TESTS() よりも前に,おそらくは main() 関数で AddGlobalTestEnvironment() を呼び出す必要があります.gtest_main を利用する場合は,これを main() の開始前に呼ぶ必要があります.これを行う方法の1つは,次のようにグローバス変数を定義することです:

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

しかし,ユーザが自分の main() を書いて,そこで AddGlobalTestEnvironment() を呼び出すことを強く勧めます. グローバル変数の初期化に依存するコードは,読みにくくなります. また,異なる翻訳単位(オブジェクトファイル)で複数の Environment オブジェクトを登録し,それらが互いに依存している場合,問題が起こる可能性があります(コンパイラは,グローバル変数の初期化順序を保証しないことを思い出してください).

利用可能な環境: Linux,Windows,Mac.

値をパラメータ化したテスト

値をパラメータ化したテスト を用いると,同じテストをコピーしなくても,異なるパラメータでコードをテストできます.

例えば,ユーザがテストを書いた後に,テスト対象のコードがコマンドラインで与えられるブール値のフラグに影響される事に気づいたとします.

TEST(MyCodeTest, TestFoo) {
  // foo() をテストするコード.
}

通常は,テストコードの一部を関数に分割して,その引数にブール値を受け取るようにします.その関数でフラグをセットし,その後テストコードを実行します.

void TestFooHelper(bool flag_value) {
  flag = flag_value;
  // foo() をテストするコード.
}

TEST(MyCodeTest, TestFooo) {
  TestFooHelper(false);
  TestFooHelper(true);
}

しかし,この初期化方法には重大な問題があります.まず,テスト中のアサーションが失敗した場合,パラメータのどのような値が失敗の原因なのかが分からなくなるという点です.EXPECT/ASSERT に識別するためのメッセージを追加することもできますが,すべてを自分でやる必要があります.2つ目の問題点として,テスト毎にこのようなヘルパ関数を書く必要があるという点が挙げられます.10個のテストがある場合はどうでしょうか? 20個なら? 100個なら?

値をパラメータ化したテストを利用すると,テストを1度だけ書き,それをインスタンス化して,任意の個数のパラメータで実行することができます.

値をパラメータ化したテストが便利な,いくつかの状況を説明します:

  • オブジェクト指向インタフェースの異なる実装をテストしたい場合
  • 様々な入力でコードをテストしたい場合(これは,データ駆動テストとして知られています).この特徴は乱用されやすいので,このような使い方をするときは是非ともセンスを磨いてください.

値をパラメータ化したテストの書き方

値をパラメータ化したテストを書くには,まずフィクスチャクラスを定義する必要があります.また,それは ::testing::Test および ::testing::WithParamInterface<T> の両方から派生しなければいけません(後者は,純粋インタフェースです).ここで T は,パラメータ値の型を表します.利便性のため,::testing::Test と ::testing::WithParamInterface<T> の両方から派生した ::testing::TestWithParam<T> から,フィクスチャクラスを派生させることもできます.Tはコピー可能な任意の型です.これが通常のポインタである場合,ユーザはポインタが示す値の管理を行う責任があります.

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) {
  // テスト内部では,TestWithParam<T> クラスの GetParam() メソッド
  // を用いてテストパラメータにアクセスしてください:
  EXPECT_TRUE(foo.Blah(GetParam()));
  ...}

TEST_P(FooTest, HasBlahBlah) {
  ...
}

最後に,任意のパラメータセットを与えたテストケースをインスタンス化するために,INSTANTIATE_TEST_CASE_P を使います. Google Test では,テストパラメータを生成するいくつかの関数を定義しています.これは,(なんと!)パラメータジェネレータ と呼ばれるものを返します.ここでは,その概要を示します.これはすべて, testing 名前空間に存在します.

   
Range(begin, end[, step]) {begin, begin+step, begin+step+step, ...} という値を生成します.end は値に含まれません.step のデフォルト値は1です.
Values(v1, v2, ..., vN) {v1, v2, ..., vN} という値を生成します.
ValuesIn(container) と ValuesIn(begin, end) C言語形式の配列,STL形式のコンテナ,またはイテレータの範囲 [begin, end) で表される値を生成します.
Bool() シーケンス {false, true} を生成します.container, begin, end という表現により,その値を実行時に決定することができます.
Combine(g1, g2, ..., gN) N 個のジェネレータから作成された値のすべての組み合わせ(数学でいうデカルト積)を生成します.これは,ユーザのシステムに <tr1/tuple> ヘッダが存在する場合のみ有効です.システムにヘッダが間違いなく存在するにも関わらず,Google Test がないという場合は,GTEST_HA S_TR1_TUPLE=1 を定義することでオーバーライドできます.詳細は, include/gtest/internal/gtest-port.h のコメントを参照してください.

詳細については, ソースコード 中でこれらの関数を定義している箇所のコメントを参照してください.

以下の文は,テストケース FooTest のテストに,それぞれパラメータ値 “meeny”,”miny”,”moe” を与えてインスタンス化します.

INSTANTIATE_TEST_CASE_P(InstantiationName,
                        FooTest,
                        ::testing::Values("meeny", "miny", "moe"));

あるパターンを持った別のインスタンス(そう,ユーザは1度以上インスタンス化できるのです)を区別するために, INSTANTIATE_TEST_CASE_P の最初の引数として,実際のテストケース名の先頭に追加されるプリフィックスを与えます.異なるインスタンスには,異なるプリフィックスを与えてください.以上のようにインスタンス化されたテストは,以下のような名前を持ちます:

  • InstantiationName/FooTest.DoesBlah/0 for “meeny”
  • InstantiationName/FooTest.DoesBlah/1 for “miny”
  • InstantiationName/FooTest.DoesBlah/2 for “moe”
  • InstantiationName/FooTest.HasBlahBlah/0 for “meeny”
  • InstantiationName/FooTest.HasBlahBlah/1 for “miny”
  • InstantiationName/FooTest.HasBlahBlah/2 for “moe”

これらの名前は, —gtest_filter で利用できます.

次の文は,FooTest の全てのテストにそれぞれ “cat” および “dog” というパラメータを与えてインスタンス化します.

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

このようにインスタンス化されたテストは,次のような名前になります.

  • AnotherInstantiationName/FooTest.DoesBlah/0 for “cat”
  • AnotherInstantiationName/FooTest.DoesBlah/1 for “dog”
  • AnotherInstantiationName/FooTest.HasBlahBlah/0 for “cat”
  • AnotherInstantiationName/FooTest.HasBlahBlah/1 for “dog”

INSTANTIATE_TEST_CASE_P は,与えられたテストケース内の 全ての テストをインスタンス化することに注意してください.テスト自体の定義が INSTANTIATE_TEST_CASE_P 文の前にあるか後にあるかは関係ありません.

これらの ファイル に,別の例が載っています.

利用可能な環境: Linux,Windows(MSVC 8.0以降が必要),Mac.バージョン 1.2.0 以降.

値をパラメータ化した抽象テスト

これまでの説明では,FooTest の定義とインスタンス化を同じソースファイル内でおこなっていました.しかし,ライブラリ内に 値をパラメータ化したテスト を定義し,後で別のユーザがそれをインスタンス化する,という使い方をしたい場合もあります. このパターンは, 抽象テスト として知られています.1つの利用例として,インタフェースを設計する場合を考えてみます.そこでは,インタフェースの実装すべてが通過できるはずの標準的な抽象テストスイートを書くことができます(おそらく,テストパラメータとしてファクトリ関数が利用されるでしょう).そして,インタフェースを実装する人は,インタフェースの適合テストを取得するために,あなたのテストスイートを自由にインスタンス化することができます.

抽象テストを定義するには, 次のようにコードを構造化する必要があります:

  1. パラメータ化されたテストのフィクスチャクラス(例えば,FooTest)の定義は,例えば foo_param_test.h という名前のヘッダファイルに書いてください. これは,抽象テストの 宣言 と見なせます.
  2. TEST_P の定義は,foo_param_test.cc に書いてください.ここでは,foo_param_test.h がインクルードされます.これは,抽象テストの 実装 と見なせます.

これが1度定義された後は,foo_param_test.h をインクルードして, INSTANTIATE_TEST_CASE_P() を呼び出し,foo_param_test.cc をリンクすることで,自由にテストをインスタンス化することができます.異なるソースファイルで,同じ抽象テストを複数回インスタンス化することができます.

型付けテスト

同じインタフェースの複数の実装があり,全ての実装がある共通の要求に対して安全であることを確認したいとします.あるいは,同じ「コンセプト」を満足するはずの複数の定義型があり,そのことを確認したいとします.どちらの場合も,同じテストロジックを異なる型に対して繰り返したい,ということになります.

テスト対象となるそれぞれの型に対して TEST_F や TEST を書くことはできますが (さらに,テストロジックの一部を関数テンプレートに分離して,それを TEST から呼び出すことになるでしょう),それは面倒でスケールしない作業です.つまり,m 個のテストを n 個の型に対して行いたい場合,m*n 個の TEST が必要になってしまいます.

型付けテスト を使うと,同じテストロジックを型のリストに対して繰り返すことができます.型付けテストを書く時点で型リストが分かっている必要がありますが,テストロジックは1度書くだけで構いません.ここでは,その方法を説明します:

まず,フィクスチャクラステンプレートを定義します.これは,型でパラメータ化する必要があります.また,::testing::Test を継承することを忘れないでください:

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

次に,型リストと,リスト内のそれぞれの型に対して繰り返されるテストケースとを関連付けます.

typedef ::testing::Types<char, int, unsigned int> MyTypes;
TYPED_TEST_CASE(FooTest, MyTypes);

typedef は,TYPED_TEST_CASE マクロが正しくパースを行うために必要です.これがないと,コンパイラは,型リスト中のカンマをマクロ引数の区切り文字と見なしてしまいます.

次に,TEST_F() の代わりに TYPED_TEST() を使って,このテストケースにおける型付けテストを定義します.必要なだけ,テストの定義を行ってください

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

  // フィクスチャの static なメンバにアクセスするには,
  // 'TestFixutre::' プリフィックスを追加します.
  n += TestFixture::shared_;

  // フィクスチャ内で typedef されたメンバにアクセスするには,'typename TestFixture::' プリフィックスを追加します.
  // 'typename' は,コンパイラに型名であることを知らせるためにあります.
  typename TestFixture::List values;
  values.push_back(n);
  ...
}

TYPED_TEST(FooTest, HasPropertyA) { ... }

TYPED_TEST(FooTest, HasPropertyA) { ... }

完全な例を見るには,samples/sample6_unittest.cc を参照してください.

利用可能な環境: Linux,Windows(MSVC 8.0以降が必要),Mac.バージョン 1.1.0 以降.

型をパラメータ化したテスト

型をパラメータ化したテスト は型付けテストと似ていますが,事前に型のリストを知っておく必要がない,という点が異なります.その代り,まずテストロジックを定義し,後から異なる型リストを与えてインスタンス化します.同じプログラム中で,複数回インスタンス化することもできます.

あなたがインタフェースやコンセプトを設計する立場ならば,インタフェース/コンセプトの実装すべてが持つべきプロパティを検証するための,型をパラメータ化したテストスイートを定義できます.そして,各実装を行う人々は,その実装が要求を満たしていることを確認するために,テストスイートをそれぞれの型でインスタンス化することができます. 以下に,例を示します:

まず,型付けテストの場合と同様に,フィクスチャクラステンプレートを定義します:

 template <typename T>
class FooTest : public ::testing::Test {
   ...
 };

次に,型をパラメータ化したテストケースを宣言します:

TYPED_TEST_CASE_P(FooTest);

この _P というサフィックスは,”Parameterized” または “pattern” を意味しますが,好きな方で考えてください.

そして,TYPED_TEST_P() を用いて,型をパラメータ化したテストを定義します.必要なだけ,テストの定義を行ってください

TYPED_TEST_P(FooTest, DoesBlah) {
  // テスト内部で型パラメータを取得するには,特別な名前 TypeParam を参照します.
  TypeParam n = 0;
  ...
}

TYPED_TEST_P(FooTest, HasPropertyA) { ... }

さて,ここがトリッキーな箇所です:これらをインスタンス化する前に,REGISTER_TYPED_TEST_CASE_P マクロを用いて全てのテストパターンを登録する必要があります.マクロの最初の引数は,テストケースの名前です.そして,それ以降の引数は,そのテストケースに属するテストの名前です.

REGISTER_TYPED_TEST_CASE_P(FooTest,
                           DoesBlah, HasPropertyA);

最後に,好きな型を与えて,自由にインスタンス化を行います.上述のコードをヘッダファイルに書けば,複数の C++ ソースファイルに #include 文を書いて,複数回インスタンス化することができます.

typedef ::testing::Types<char, int, unsigned int> MyTypes;
INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes);

このパターンにおける異なるインスタンスを区別するために,INSTANTIATE_TYPED_TEST_CASE_P マクロの最初の引数として,実際のテストケース名の先頭に追加されるプリフィックスを渡します.異なるインスタンスには,異なるプリフィックスを与えてください.

型リストが 1 つの型しか含まない特別な場合は,::testing::Types<...> なしで直接,次にように書くことができます.

INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, int);

完全な例を見るには,samples/sample6_unittest.cc を参照してください.

利用可能な環境: Linux,Windows(MSVC 8.0以降が必要),Mac.バージョン 1.1.0 以降.

Private コードのテスト

ソフトの内部的実装を変更しても,ユーザからその変更が見えない限りは,テストは失敗するべきではありません.よって, ブラックボックステストの原則 に従い,大部分のコードテストは public インタフェースを使って行われるべきです.

もし,まだ内部的な実装コードをテストする必要があるならば,そうしなくてもよい設計がないかどうか考えてください.しかし,どうしても public ではないインタフェースを通してテストを行わなければならない場合は,そうすることもできます.2つの場合を考えてみましょう:

  • static な関数( static なメンバ関数という意味ではありません),または匿名の名前空間
  • private または protected なクラスメンバ

Static な関数

匿名の名前空間に属する static な関数とその定義/宣言はどちらも,同じ翻訳単位からのみ参照できます.それらをテストするために,*_test.cc ファイル内で,テスト対象となる .cc ファイル全体を #include することができます.(コードを再利用するために .cc ファイルをインクルードするのは良い方法とはいえません - 製品版のコードでは,このようなことしないでください!)

しかし,より良い方法は,private なコードを foo::internal 名前空間に移動し, private 宣言を *-internal.h で行うことです.ここで,foo は,プロジェクトで通常使用している名前空間です.製品版の .cc ファイルやテストからは,この internal ヘッダをインクルードすることができますが,顧客側からはできません.この方法では,内部実装を顧客側に晒すことなく完全にテストができます.

Private クラスメンバ

private なクラスメンバは,そのクラスや friend クラスからのみアクセス可能です.クラスの Private メンバにアクセスするには,テストフィクスチャをそのクラスの friend として宣言して,フィクスチャクラスにアクセサを定義します.そして,そのフィクスチャを利用するテストは,フィクスチャのアクセサを介してクラスの private メンバにアクセスできます. フィクスチャクラスは製品版クラスの friend ではありますが,テストも自動的にその friend になるわけではなく,フィクスチャの派生クラスとして定義されることに注意してください.

private なメンバをテストするもう1つの方法は,そのメンバを実装クラスとして書き出し,宣言だけを *-internal.h ファイル内で行うことです.顧客側は,このヘッダファイルをインクルードできませんが,テストからはインクルード可能です.これは,Pimpl(Private Implementation)イディオムと呼ばれます.

次のような行をクラスに追加して,個々のテストをクラスの friend として宣言する,という方法もあります.

 FRIEND_TEST(TestCaseName, TestName);
 For example,

 // foo.h
 #include "gtest/gtest_prod.h"

 // FRIEND_TEST を定義します
 class Foo {
   ...
  private:
   FRIEND_TEST(FooTest, BarReturnsZeroOnNull);
   int Bar(void* x);
};

 // foo_test.cc
 ...
 TEST(FooTest, BarReturnsZeroOnNull) {
   Foo foo;
   EXPECT_EQ(0, foo.Bar(NULL));
   // Foo の private メンバ Bar() を使います.
 }

あなたのクラスがある名前空間内で定義されている場合は特に注意してください.つまり,テストフィクスチャとテストを,あなたのクラスの friend としたいならば,それらは同じ名前空間内で定義する必要があります.例えば,次のようなコードをテストしたいとします:

namespace my_namespace {

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

}  // my_namespace 名前空間

この場合,テストコードは次のようになります:

namespace my_namespace {
class FooTest : public ::testing::Test {
protected:
  ...
};

TEST_F(FooTest, Bar) { ... }
TEST_F(FooTest, Baz) { ... }

}  // my_namespace 名前空間

失敗をキャッチする

Google Test を使ってテストユーティリティを作ると,そのテストユーティリティのテストをしたくなります. そのテストには,何のテストフレームワークを使いたいですか?もちろん Google Test ですよね.

ここでの問題は,あなたのテストユーティリティが正しく失敗を報告するかどうかを検証することです.例外を投げることで失敗を報告するフレームワークでは,それをキャッチしてアサートすることもできるでしょう.しかし,Google Test では例外を利用しません.コードが期待通りに失敗を生成するかどうかを,どうやってテストすればいいのでしょうか?

“gtest/gtest-spi.h” には,これを行うためのクラス類が含まれています. このヘッダをインクルードすると,次のマクロを利用できます.

 
EXPECT_FATAL_FAILURE(statement, substring);

これは,致命的な失敗(例えば,ASSERT_*)を生成する statement をアサートします.この失敗メッセージには,与えられた substring が含まれます.

 
EXPECT_NONFATAL_FAILURE(statement, substring);

致命的ではない失敗(例えば,EXPECT_*)を想定する場合は,こちらを利用してください.

技術的な理由により,いくつの制限があります:

どちらのマクロでも,失敗メッセージをストリームに出力することができません. EXPECT_FATAL_FAILURE() の statement は,static ではないローカル変数や,this オブジェクトの static ではないメンバを参照できません. EXPECT_FATAL_FAILURE() の statement は,値を返すことはできません.

注意 : Google Test はスレッドを考慮して設計されています.1度 “gtest/internal/gtest-port.h” の同期プリミティブがインスタンス化されると,Google Test はスレッドセーフになります.つまり,それ以降はマルチスレッドで同時にアサーションを利用できます.

しかし,それ以前では,シングルスレッドでのみ利用できます.1度スレッドセーフになると,EXPECT_FATAL_FAILURE() と EXPECT_NONFATAL_FAILURE() は,現在のスレッドにおける失敗だけをキャッチするようになります.statement が新しいスレッドを作成する場合も,そのスレッドでの失敗は無視されます.もし全てのスレッドでの失敗をキャッチしたい場合は,次のマクロを利用する必要があります.

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

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

現在実行しているテストの名前が必要になる事態が考えられます.例えば,テストフィクスチャの SetUp() メソッド中で,期待値の書かれたファイル名を実行中のテストに基づいて決めることがあるかもしれません.::testing::TestInfo クラスには,この情報が入っています.

namespace testing {

class TestInfo {
 public:
  // それぞれ,テストケース名とテスト名を返します.
  //
  // 返されるポインタは TestInfo クラスで管理されるので,
  // 削除したり解放したりしないでください.
  const char* test_case_name() const;
  const char* name() const;
};

}  // namespace testing

実行中のテストに対する TestInfo オブジェクトを取得するには, UnitTest シングルトンオブジェクトで current_test_info() を呼び出してください.

// 現在実行中のテストに関する情報を取得します.
// 返されるオブジェクトは UnitTest クラスで管理されるので,削除しないでください.
const ::testing::TestInfo* const test_info =
printf("We are in test %s of test case %s.\n",
       test_info->name(), test_info->test_case_name());

テストが実行中でない場合, current_test_info() は,NULLポインタを返します.具体的に言えば,TestCaseSetUp() や TestCaseTearDown() (この時点で,テストケース名は既に分かっているわけですが),そこから呼び出される関数では,テストケース名を取得することはできません.

利用可能な環境: Linux,Windows,Mac.

テストイベントをハンドリングして Google Test を拡張する

Google Test にはイベントリスナー API が用意されており,テストプログラムの進捗やテストの失敗に関する通知を受け取ることができます. 受け取ることができるイベントは,テストプログラムやテストケース,テストメソッドなどの開始と終了です. このAPIを利用して,コンソールへの標準出力の拡張,置き換えを行ったり,XML 出力を置き換えたり,さらには GUI やデータベースのように出力形式が全く異なるものを提供したり,といったことが可能になります.例えば,リソースリークチェッカーを実装するためのチェックポイントとして,テストイベントを利用できます.

利用可能な環境: Linux,Windows,Mac.バージョン 1.4.0 以降.

イベントリスナーの定義

イベントリスナーを定義するためには, testing::TestEventListener または testing::EmptyTestEventListener を継承します.前者は(抽象)インタフェースで,その純仮想メソッドがオーバーライドされ,テストイベントとして扱われます(例えば,テストが開始したときに OnTestStart() メソッドが呼び出されます).後者が提供するインタフェースメソッドの実装はすべて空で,派生クラスで必要なメソッドだけをオーバーライドします.

イベントが起こると,そのコンテキストがハンドラ関数の引数に渡されます.渡される引数の型は,次に示すとおりです:

  • UnitTest は,テストプログラム全体の状態を反映するものです.
  • TestCase は,テストケースに関する情報を持ちます.テストケースには,1つ以上のテストが含まれます.
  • TestInfo は,テストの状態に関するものです.
  • TestPartResult は,テストアサーションの結果を表します.

イベントハンドラ関数は,渡された引数を検査して,そのイベントとテストプログラムの状態に関する情報を得ることができます.次に例を示します:

class MinimalistPrinter : public ::testing::EmptyTestEventListener {
  // テスト開始前に呼ばれます.
  virtual void OnTestStart(const ::testing::TestInfo& test_info) {
    printf("*** Test %s.%s starting.\n",
           test_info.test_case_name(), test_info.name());
  }

  // アサーションが失敗した後,または SUCCEED() が実行された後に呼ばれます.
  virtual void OnTestPartResult(
      const ::testing::TestPartResult& test_part_result) {
    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());
  }

  // テスト終了後に呼ばれます.
  virtual void OnTestEnd(const ::testing::TestInfo& test_info) {
    printf("*** Test %s.%s ending.\n",
           test_info.test_case_name(), test_info.name());
  }
};

イベントリスナーを利用する

定義したイベントリスナーを使うには,そのインスタンスを Google Test イベントリスナーリスト(これは, TestEventListeners クラスで表されます.最後の “s” に注意してください)に登録します.この登録作業は,main() 関数内で RUN_ALL_TEST() を呼ぶよりも前に行います.

 int main(int argc, char** argv) {
   ::testing::InitGoogleTest(&argc, argv);
   // イベントリスナーリストを取得します.
   ::testing::TestEventListeners& listeners =
       ::testing::UnitTest::GetInstance()->listeners();
   // 末尾にリスナーを追加します.Google Test に所有権が移ります.
   listeners.Append(new MinimalistPrinter);
   return RUN_ALL_TESTS();
}

ここで1つ問題があります:テスト結果のデフォルト出力リスナーもまだ生きているので,その出力が,あなたのリスナーからの出力と混ざってしまいます.デフォルトの出力を抑制するには,それをイベントリスナーリストから外して削除してください.そのためには,以下のように1行追加します:

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

後は,テストが今までとはまったく違う出力をする様子を堪能してください.さらに詳細を知りたい場合は, サンプル を参照できます.

リストに2つ以上のリスナーを追加する可能性もあります.On*Start() または OnTestPartResult() イベントが起こると,リスナーはリストに並んだ順にそれを受け取ります(新しいリスナーはリストの末尾に追加されていくので,デフォルト出力リスナーとデフォルトXMLジェネレータが最初にイベントを受け取ります).また,On*End() イベントは,それとは 逆の 順番で受け取られます.これによって,前のリスナーの出力に後のリスナーの出力を追加していくことができます.

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

イベントを処理する際に,失敗を生成するマクロ(EXPECT_*(),ASSERT_*(),FAIL(),など)を利用することがあります.これには,いくつかの制限があります:

  1. OnTestPartResult() の中では失敗を生成することはできません(そうしないと, OnTestPartResult() が再帰的に呼ばれてしまいます).
  2. OnTestPartResult() をハンドルするリスナーも,失敗を生成することはできません.

リスナーリストにリスナーを追加する際,OnTestPartResult() をハンドルするリスナーは,失敗を生成する可能性のあるリスナーよりも前に置く必要があります.こうすることで,後者のリスナーによって生成された失敗は,正しく実行されたテストによるものであることが前者のリスナーによって保障されることになります.

失敗を生成するリスナーのサンプルは, ここ にあります.

テストプログラムを実行する:高度なオプション

Google Test のテストプログラムは,通常の実行ファイルです.1度ビルドされると,直接実行することができますし,以下の環境変数やコマンドラインフラグを用いて挙動を変更することもできます.フラグを利用するには,プログラムで RUN_ALL_TESTS() を呼ぶ前に ::testing::InitGoogleTest() を呼ばなければいけません.

サポートされるフラグと使い方の一覧を見るには,テストプログラムに —help フラグを付けて実行してみてください.-h や -?,/? などの短縮形も利用できます.この機能は,バージョン 1.3.0 で追加されました.

環境変数とフラグの両方でオプションが指定されると,フラグのほうが優先されます.オプションの大部分は,コード内でも設定/読み込みが可能です:コマンドラインフラグ —gtest_foo の値にアクセスするには,::testing::GTEST_FLAG(foo) とします.よくあるのは,フラグのデフォルト値を変更するために,::testing::InitGoogleTest() を呼ぶ前にフラグの値をセットするというパターンです:

int main(int argc, char** argv) {
  // 経過時間表示をデフォルトで無効にします.
  ::testing::GTEST_FLAG(print_time) = false;

  // これにより,コマンドラインフラグを上書きできます.
  ::testing::InitGoogleTest(&argc, argv);

  return RUN_ALL_TESTS();
}

テストを選択する

このセクションでは,実行するテストを選択するための様々なオプションを説明します.

テスト名の一覧

例えばテストをフィルタでふるい分けるために,プログラム実行前に,有効なテスト一覧を必要とする場合があります. —gtest_list_tests フラグは,他のフラグをすべて上書きして,次のようなフォーマットのテスト一覧を取得します:

TestCase1.
  TestName1
  TestName2
TestCase2.
  TestName

このフラグが与えられた場合に一覧に挙げられたテストは,実際には実行されません.また,このフラグに対応する環境変数はありません.

利用可能な環境: Linux,Windows,Mac.

テストの部分的な実行

デフォルトでは,Google Test プログラムは,ユーザが定義したすべてのテストを実行します.しかし,ある一部のテストだけを実行したい場合もあるでしょう(例えば,デバッグ時や変更をすばやく確認したい場合など).GTEST_FILTER 環境変数,または —gtest_filter フラグでフィルタ文字列を設定すると,Google Test は,(TestCaseName.TestName の形式で表される)名前全体がフィルタにマッチするテストだけを実行します.

フィルタのフォーマットは,’:’ で区切られたワイルドカードパターンのリスト(ポジティブパターン)と,’:’ で区切られた別のパターンの先頭に ’-’ がついたリスト(ネガティブパターン)です.任意のポジティブパターンにマッチし,どのネガティブパターンにもマッチしなかった場合のみ,そのテストはフィルタにマッチしたとみなされます.

パターンには,’*’(任意の文字列にマッチ)や ‘?’(任意の1文字にマッチ)が含まれる場合があります.利便性のため,フィルタ ‘*-NegativePatterns’ は,’-NegativePatterns’ と書くこともできます.

以下に例を示します:

  • ./foo_test は,フラグなしの状態です.全てのテストが実行されます.
  • ./foo_test —gtest_filter=* も全てのテストが実行されます.* は任意の文字列にマッチします.
  • ./foo_test —gtest_filter=FooTest.* は,テストケース FooTest 内の全てのテストを実行します.
  • ./foo_test —gtest_filter=*Null*:*Constructor* では,完全な名前に “NULL” または “Constructor” を含むテストが全て実行されます.
  • ./foo_test —gtest_filter=-*DeathTest.* は,Death テスト以外を実行します.
  • ./foo_test —gtest_filter=FooTest.*-FooTest.Bar は,テストケース FooTest 内の全てのテストが実行されます.ただし, FooTest.Bar は除きます.

利用可能な環境: Linux,Windows,Mac.

テストを一時的に無効にする

もし失敗するテストがあり,それがすぐには直せない場合,そのテストの名前に DISABLE_ プレフィックスをつけることができます.すると,そのテストは実行されません.無効にしたテストもコンパイルはされる(よって,いつの間にかコンパイルできなくなることもない)ので,これは,#if 0 でコードをコメントアウトするよりも良い方法です.

あるテストケースの全てのテストを無効にする必要があるなら,DISABLED_ を各テスト名の先頭に付けることもできますが,テストケース名の先頭に追加することもできます.

例えば,以下のテストはコンパイルはされますが,Google Test では実行されません:

// Foo が Abc するかどうかのテスト.
TEST(FooTest, DISABLED_DoesAbc) { ... }

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

//  Bar が Xyz するかどうかのテスト.
TEST_F(DISABLED_BarTest, DoesXyz) { ... }

注意 : この機能は,一時的な対処として使うべきものです.無効にしたテストは,後で修正しなければいけません.テストプログラムに無効なテストが含まれているときには,Google Test がリマインダーとしてバナー警告を表示します.

ヒント: 無効なテストの数は grep を使って簡単に数えることができます.この個数は,テスト品質改善の指標として利用できます.

利用可能な環境: Linux,Windows,Mac.

無効にしたテストを一時的に有効にする

無効にしたテスト を実行するには, —gtest_also_run_disabled_tests フラグを付けて,または 環境変数 GTEST_ALSO_RUN_DISABLED_TESTS を 0 以外に設定してからテストプログラムを実行するだけです.これを —gtest_filter フラグと組み合わせて,無効化されたテストのどれを実行するかを選択することもできます.

利用可能な環境: Linux,Windows,Mac.バージョン 1.3.0 以降.

テストを繰り返す

たまに,成功したり失敗したりするテストに出くわすことがあります.1% の割合で失敗するバグで,デバッガを使って再現するのがかなり難しいこともあります.このようなバグが,フラストレーションの原因になります.

—gtest_repat フラグを利用すると,プログラム中の全ての(または,選択された)テストメソッドを複数回繰り返すことができます.上手くいくと,そのテストが失敗してデバッグのチャンスが生まれるかもしれません.この使い方は以下の通りです:

   
$ foo_test —gtest_repeat=1000 foo_test を 1000 回繰り返します.失敗しても停止しません.
$ foo_test —gtest_repeat=-1 負の数を与えると,無限に繰り返します.
$ foo_test —gtest_repeat=1000 —gtest_break_on_failure foo_test を 1000 回繰り返しますが,最初の失敗で停止します.これは特に,デバッガ上で実行している場合に役立ちます:テストが失敗したときに,デバッガに移動し,変数やスタックを調べることができます.
$ foo_test —gtest_repeat=1000 —gtest_filter=FooBar フィルタにマッチする名前のテストを 1000 回繰り返します.

AddGlobalTestEnvironment() によって登録されたグローバル set-up/tear-down コードが含まれる場合,それが低い再現性の原因になっている可能性もありますが,その登録も各繰り返しで毎回行われます. 環境変数 GTEST_REPEAT をセットすることで,繰り返し回数を指定することもできます.

利用可能な環境: Linux,Windows,Mac.

テストをシャッフルする

—gtest_shuffle フラグを利用する(または環境変数 GTEST_SHUFFLE を 1 にセットする)ことで,プログラム中のテストをランダムな順序で実行できます.これによって,テスト間に良くない依存関係がないかを調べることができます.

Google Test は,デフォルトで,現在時刻から計算されたランダムシードを利用します.したがって,実行するたびに,その実行順序はバラバラになります.テスト順序に依存する失敗を後で再現できるように,ランダムシードの値はコンソールにも出力されます. ランダムシードを明示的に指定するには,—gtest_random_seed=SEED(または環境変数 GTEST_RANDOM_SEED)を利用してください.ここで,SEED は,0 から 99999 の範囲にある整数です.シード値 0 は特別な値です:これが指定されると,Google Test は,現在の時刻からシード値を計算するデフォルトの動作を行います.

これと,—gtest_repeat=N を組み合わせると,Google Test は,各繰り返しにおいて異なるランダムシードでシャッフルされたテストを行います..

利用可能な環境: Linux,Windows,Mac.バージョン 1.4.0 以降.

テストの出力を制御する

このセクションでは,報告テスト結果をカスタマイズする方法について説明します.

色付きのターミナル出力

Google Test では,テストのうち成功したテストはどれかを簡単に見分けられるように,ターミナル出力に色を付けることができます.

環境変数 GTEST_COLOR または —gtest_color フラグに,yes ,no ,auto(デフォルト)を与えることができます.それぞれ,色付き,色なし,Google Test が自動決定,という事を意味します.auto が指定された場合,出力対象がターミナルで,かつ(Windows 以外のプラットフォームで)環境変数 TERM が xterm または xterm-color にセットされている場合のみ,色を利用します.

利用可能な環境: Linux,Windows,Mac.

経過時間表示を抑制する

Google Test は,デフォルトで各テストの実行時間を表示します.これを抑制するには,—gtest_print_time=0 フラグを付けてテストプログラムを実行します.また,環境変数 GTEST_PRINT_TIME に 0 をセットしても同じです.

利用可能な環境: Linux,Windows,Mac.(バージョン 1.3.0 以前の Google Test では,経過時間を表示しない のがデフォルト動作です)

XMLレポート

Google Test では,通常のテキスト出力に加えて,XML 形式のレポートをファイルに出力できます. このレポートには各テストの実行時間が出力されており,どのテストに時間がかかっているのかを知ることができます.

XMLレポートを出力するには,環境変数 GEST_OUTPUT または —gtest_output フラグに,文字列 “xml:_path_to_output_file_” をセットします.指定された場所にファイルが作られます. test_detail.xml という名前のファイルをカレントディレクトリに出力する場合は,単に “xml” とだけ指定することもできます.

ディレクトリを指定すると(例えば,Linux では “xml:output/directory/” ,Windows では “xml:outputdirectory”),Google Test は,テスト実行ファイルに基づいた名前の XML ファイルをそのディレクトリに作成します(例えば,foo_test または foo_test.exe というテストプログラムの場合,foo_test.xml ).そのファイルが既に存在する場合(おそらくは,前回の実行結果が残っているのでしょう),Google Test は上書きしないように,違う名前(例えば, foo_test_1.xml)で保存します.

レポートで利用されるフォーマットについて説明します.これは junitreport Ant タスクに基づいており, Hudson のような有名な continuous build system で解析することができます.このフォーマットは元々 java を意識したものだったので,それを Google Test のテストに適用するには,次のように少しだけ読み替えが必要です:

<testsuites name="AllTests" ...>
  <testsuite name="test_case_name" ...>
    <testcase name="test_name" ...>
      <failure message="..."/>
      <failure message="..."/>
      <failure message="..."/>
    </testcase>
  </testsuite>
</testsuites>
  • ルート要素 <testsuites> は,テストプログラム全体に対応します.
  • 要素 <testsuite> は,Google Test のテストケースに対応します.
  • 要素 <testcase> は,Gogle Test のテスト関数に対応します.

例えば,次のプログラム

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

は,次のレポートを生成します

<?xml version="1.0" encoding="UTF-8"?>
<testsuites tests="3" failures="1" errors="0" time="35" name="AllTests">
  <testsuite name="MathTest" tests="2" failures="1"* errors="0" time="15">
    <testcase name="Addition" status="run" time="7" classname="">
      <failure message="Value of: add(1, 1)&#x0A; Actual: 3&#x0A;Expected: 2" type=""/>
      <failure message="Value of: add(1, -1)&#x0A; Actual: 1&#x0A;Expected: 0" type=""/>
    </testcase>
    <testcase name="Subtraction" status="run" time="5" classname="">
    </testcase>
  </testsuite>
  <testsuite name="LogicTest" tests="1" failures="0" errors="0" time="5">
    <testcase name="NonContradiction" status="run" time="5" classname="">
    </testcase>
  </testsuite>
</testsuites>

注意事項:

  • 要素 <testsuites> や <testsuite> の属性 tests は,Google Test プログラム,またはテストケースに含まれるテスト関数の個数を表し,属性 failures は,そのうち失敗したテスト関数の個数を表します.
  • 属性 time は,そのテスト,テストケース,テストプログラム全体の実行時間をミリ秒単位で表します.
  • 1つの要素 <failure> は,失敗した Google Test アサーション1つに対応します.
  • Google Test には適用されない JUnit コンセプトもありますが,今のところ DTD には従う必要があります.よって,レポート中にダミー要素やダミー属性が含まれることがあります.それらは無視しても安全です.

利用可能な環境: Linux,Windows,Mac.

失敗のレポート方法を制御する

アサーション失敗箇所にブレークポイントを設置する

デバッガ上でテストプログラムを実行しているとき,デバッガがアサーションの失敗をキャッチして自動的にインタラクティブモードに移行してくれると非常に便利です.Google Test の break-on-failure モードは,この動作をサポートします.

これを有効にするには,環境変数 GTEST_BREAK_ON_FAILURE に 0 以外の値をセットします.または, —gtest_break_on_failure フラグを利用することもできます.

利用可能な環境: Linux,Windows,Mac.

テストが投げる例外のキャッチを無効化する

Google Test は,例外が有効な環境と無効な環境のどちらでも利用できます.テストが C++ 例外や(Windows で)構造化例外(SEH)を投げる場合, Google Test は,デフォルトでそれをキャッチして,テスト失敗として報告します.そして,次のテストメソッドを引き続き実行します.これによって,テスト実行のカバレッジが最大化されます.また,Windows 環境においては,例外を捕まえなかった場合にポップアップウィンドウが出現するので,自動的なテスト実行のためには例外をちゃんと捕まえることが必要です.

しかし,失敗したテストのデバッグを行っているとき,例外が投げられた時のコールスタックを調査するために,その例外をデバッガでハンドルしたいと思うことがあるかもしれません.そのためには,GTEST_CATCH_EXCEPTIONS 環境変数を 0 にセットするか,テスト実行時に —gtest_catch_exception=0 フラグを利用してください.

利用可能な環境: Linux,Windows,Mac.

別の Testing Framework と一緒に使う

既に別の testing framework を利用するプロジェクトで作業をしていて,Google Test に完全に切り替える準備がまだ整っていないならば,既存のテスト中で Google Test のアサーションを利用することで,Google Test の恩恵の大半を享受でます. main() 関数を次のように変更してください:

#include "gtest/gtest.h"

int main(int argc, char** argv) {
  ::testing::GTEST_FLAG(throw_on_failure) = true;
  // 重要:Google Test は必ず初期化してください.
  ::testing::InitGoogleTest(&argc, argv);

  ... whatever your existing testing framework requires ...
}

こうすることで,既存の testing framework が提供するアサーションに加え,Google Test のアサーションを利用することができます.例を示します:

void TestFooDoesBar() {
  Foo foo;
  EXPECT_LE(foo.Bar(1), 100);     // Google Test のアサーション.
  CPPUNIT_ASSERT(foo.IsEmpty());  // 元々のアサーション.
}

Google Test のアサーションが失敗すると,エラーメッセージを表示して例外を投げます.この例外は,testing framework によって失敗として扱われます.例外を無効にしてコードをコンパイルした場合,Google Test のアサーションが失敗すると,0 ではない終了コードでプログラムが終了します.これも,テスト失敗のシグナルを testing framework に送信します.

もし,main() に ::testing::GTEST_FLAG(throw_on_failure) = true; を書かない場合,代わりに,—gtest_throw_on_failure フラグを指定するか,環境変数 GTEST_THROW_ON_FAILURE を 0 以外の値にセットすることでこの機能を有効にできます.

利用可能な環境: Linux,Windows,Mac.バージョン 1.3.0 以降.

テスト関数を複数のマシンに分散する

テストプログラムを実行するためのマシンが2台以上ある場合,テスト関数を並列に実行して,より早く結果を得たいと考えるかもしれません.我々は,この技術を sharding ,各マシンを shard と呼んでいます..

Google Test は,test sharding と互換性があります.この機能を利用するには,テストランナー(Google Test のことではありません)が次のことを行う必要があります:

  • テストを実行するために複数台のマシン(shards)を割り当てます.
  • 各 shard で,環境変数 GTEST_TOTAL_SHARDS に shard の総数をセットします.これは,すべての shard で同じ値になります.
  • 各 shard で,環境変数 GTEST_SHARD_INDEX に,その shard のインデックスをセットします.異なる shard には,異なるインデックスが割り当てられます.インデックスは,必ず [0, GTEST_TOTAL_SHARDS - 1] の範囲内の値です.
  • すべての shard 上で,同じテストプログラムを実行します.Google Test は上述の環境変数を確認して,実行するテスト関数のサブセットを選択します.プログラムの1つのテスト関数は,すべての shard に渡って 1度だけ実行されます.
  • すべての shard が終了するのを待ち,結果レポートが集められます.

プロジェクトの中に Google Test を使わずに書かれたテストが混ざっていて,このプロトコルを理解できないかもしれません.どのテストが sharding をサポートしているかを,テストランナー側が検出するために,環境変数 GTEST_SHARD_STATUS_FILE に存在しないファイルパスをセットします.テストプログラムが sharding をサポートしていれば,それを知らせるためにファイルが作られます(今回の場合,実際のファイルの中身は重要ではありません.将来的には,ここに有用な情報を載せるかもしれませんが).sharding がサポートされていなければ,ファイルが作られません.

分かりやすい例を示します.次の 5 個のテスト関数を含むテストプログラム foo_test を考えてください:

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 を実行します.

Google Test には,shard 間で仕事がどのように分散されるかを変更する権限がありますが,ここでは1つの事例を示すにとどめます:

Machine #0 runs A.V and B.X.
Machine #1 runs A.W and B.Y.
Machine #2 runs B.Z.

利用可能な環境: Linux,Windows,Mac.バージョン 1.3.0 以降.

Google Test のソースファイルを結合する

Google Test の実装は,(自身のテストを除いて)約 30 のファイルから構成されます.新しいマシンに簡単にコピーして使うために,これらを 2つのファイル(.h と .cc )にまとめたい場合があります. scripts/ ディレクトリに,このための実験的な Python スクリプト fuse_gtest_files.py を用意しています(バージョン 1.3.0 以降).マシンに Python 2.4 以降がインストールされていれば,そのディレクトリに移動して,次のように実行

python fuse_gtest_files.py OUTPUT_DIR

すると,OUTPUT_DIR ディレクトリに,gtest/gtest.h と gtest/gtest-all.cc が作成されているはずです.これらのファイルには,Google Test を使うためのすべてが含まれています.これらを好きな場所にコピーするだけで,テストを書く準備が整います.これを使ってテストをコンパイルする例として,ファイル scripts/test/Makefile が参考になります.

次のステップ

おめでとうございます.さて, Google Test のより高度な使い方を学び,さらに複雑なテストに取り組む準備ができました.さらに深い理解を求めるなら, よくある質問 を読んでください.

目次

このページ