テスト ケースの特定の要件に合わせて、スタブの振る舞いは動的に設定することができます。スタブ構成は、専用の API を使ってソース コード中で定義します。スタブ構成を指定できる場所は、テスト スイートの setup/teardown、テスト ケースの setup/teardown、およびテスト ケース内です。テスト ケース内に作成したスタブ構成は、テスト ケースの実行後にすぐに削除されます。同様に、テスト ケースやテスト スイートの setup() 関数で指定したスタブ構成は、それぞれの teardown() 関数の実行後にすぐに削除されます。

スタブの振る舞いのユーザー定義は、“トリガー オブジェクト”によって内部的に表現されます。トリガー オブジェクトを定義すると、指定した演算子、値、および引数参照が累積されます。実行されたトリガーは、定義された操作を実施します。トリガー オブジェクトの実行は、トリガー オブジェクトの定義時に名前で参照された引数の実際の値で補完されます。以下の表は、スタブの振る舞い定義 (トリガー オブジェクト) を指定および実行するために使用されるマクロです。

マクロ

定義

CPPTEST_ON_CALL(func-id)[definition]

スタブの振る舞いを定義します (トリガー オブジェクトを作成します)。通常、テスト ケースの本体で指定されます。

CPPTEST_AFTER_CALL(func-id)[definition]

オリジナルの関数/メソッドがスタブから呼び出された後にだけ実行される、追加の (オプション) の振る舞いを定義します (トリガー オブジェクトを作成します)。通常、テスト ケースの本体で指定されます。

CPPTEST_ACTUAL_CALL(func-id)[args]

定義されたスタブの振る舞いを実行します。常にスタブ内に置かれます。

CPPTEST_ACTUAL_AFTER_CALL(func-id)[args]

オリジナル関数/メソッドの呼び出し後の処理に対して定義された振る舞いを実行します。常にスタブ内に置かれます。

  • definition: 期待されるスタブの振る舞いを定義する、スタブ API への呼び出しシーケンス。  
  • args: スタブの振る舞いの実行に渡される引数シーケンス。  
  • func-id: スタブを特定するために使用される文字列。デフォルトでは、C++test が生成するスタブは以下のパターンに従って識別子を使用します。
    [parent::]<function_name>
    接頭辞 parent:: は、関数/メソッドがクラス メンバーまたは名前空間メンバーである場合にだけ追加されます。直接の親だけが追加されます。テンプレート クラス メソッドの場合、親の名前でテンプレート パラメーターは省略されます。  

C++test は、関数のすべてのオーバーロードに対して同じスタブ関数識別子を使用します。必要に応じて、スタブ定義を変更することで、オーバーロードされたスタブ関数ごとに固有のスタブ関数識別子を用意できます。そうすることで、オーバーロードされた関数/メソッドのスタブを区別できます。

以下の表に挙げる例は、データと制御フローを可視化するためにテスト ケース (C++ API) と共に使用されるスタブ本体を非常に簡潔にしたものです。


テスト ケース定義

スタブ定義

void testCase1
{
CPPTEST_ON_CALL("foo")
  If().Arg("param1").Equal(0).Fail("Problem").
  Arg("__return").Assign(3);

int __return =  goo(a);

  CPPTEST_ASSERT(__return == 5);
}

int foo(int param1, int param2);
 
int CppTest_Stub_foo (int param1, int param2)
{
int __return = 0;
int __callOrig = 0;
 
  CPPTEST_ACTUAL_CALL("foo").
    WithArg("param1", ByRef(param1)).
    WithArg("param2", ByRef(param2)).
    WithArg("__return", ByRef(__return)).
    WithArg("__callOrig", ByRef(__callOrig)).
    End();
 
if (_callOrig) {
int _return = foo(a);
    CPPTEST_ACTUAL_AFTER_CALL("foo").
      WithArg("a", ByRef(a)).
      WithArg("__return", ByRef(__return)).
      End();
return __return;
  }
return __return;
}

この例では、関数 foo() のスタブが以下のように振る舞います。

  • param1 の値を 0 に対してテストし、parasm10 に等しい場合、問題メッセージをレポートします。  
  • __return トリガー引数に整数値 3 を代入します。これはスタブから返される変数を表します。  

スタブの振る舞いの定義には、代入、論理演算子、関係演算子、算術演算、および実行コールバック関数を含めることができます。スタブの振る舞い定義の文法の詳細については 「Stubs API Reference」を参照してください。C 言語と C++ 言語では、スタブ API に違いがあります。文法の説明の中で、すべての違いを強調表示し、例を挙げています。特に重要なのは以下の違いです。

  • C 言語と C++ 言語では、スタブの振る舞いを定義するときに一連のメソッド/関数を呼び出すために使用する演算子が異なります。C++ の API はドット演算子 (.) を使用します。C のAPI は矢印演算子 (->) を使用します。  
  • スタブの振る舞い定義で値を指定する場合、C では値を渡すために型に特化したメソッドを必要とします。一方、C++ では単一のオーバーロードされたメソッドを使用できます。  

上記の例に出てくるスタブの振る舞いの定義は、C 言語では以下のようになります。


CPPTEST_ON_CALL("foo")->If()->Arg("param1")->Equal()->Int(0)->Assert("Problem")->Arg("__return")->Assign(3); 

ドット演算子 (.) の代わりに矢印演算子 (->) が使用している点と、整数値を渡すために Int() 関数呼び出しを使用している点に注意してください。

スタブの振る舞いの定義で引数を指定する

スタブの振る舞い定義では、名前によって、あるいは引数名に評価される式によって、引数を指定できます。前の例の param1__return で示すように、スタブ内の定義された振る舞いの実行中に、名前付き引数の実際の値が提供されます。

以下の表は、スタブの振る舞い定義に引数を指定するための API メソッドです。

API メソッド

説明

Arg(const char *argName)

引数は、文字列として提供される名前によって決定されます。CPPTEST_ACTUAL_CALL と CPPTEST_ACTUAL_AFTER_CALL で使用する名前は正確に一致しなければなりません。
例:

[TestCase] CPPTEST_ON_CALL("foo").Arg("param1").Assign(0); [Stub] CPPTEST_ACTUAL_CALL(“foo”).WithArg(“param1”, ByRef(“param1”).End(); 

ArgByExpr()

引数は、その後の式を評価することで決定され、const char * 型でなければなりません。
例:
CPPTEST_ON_CALL(“foo”).ArgByExpr().Arg(“argName”).Assign(0);
 
{Arg(“arg_name”)} は、“char *” 型の値に対するスタブの実行中に評価されると推測され、これが引数名として使用されます。したがって以下のようになります。

{ArgByExpr().Arg(“argName”)}=>{Arg(<value of Arg(“argName”)>)}

C++test が生成するスタブは、デフォルト引数に以下の名前付け規則を使用します。

  • (スタブ化された関数/メソッドのパラメーターを反映する) スタブのパラメーターは、オリジナルの関数/メソッド定義で指定されているように名前によって利用可能です。  
  • スタブからの戻り値に使用される変数は、__return という名で利用可能です。  
  • オリジナルのシンボル定義への呼び出しにリダイレクトするための条件として使用される変数は、__callOrig という名で利用可能です。  

スタブの振る舞いの定義で値を指定する

スタブの振る舞い定義における操作のための値は、"値によって" または "参照によって" 提供することができます。機能的にはこれは C/C++ と同じ概念です。lvalue の振る舞いが期待される場合、渡す値は ByRef() 関数への呼び出しでラップしなければなりません。rvalue が期待される状況では、ByRef() を使って値をラップする必要はありません。

通常、参照で変数を渡すことが望ましいのは、代入が期待される場合、またはスタブが実行されるまで実際の値の評価を延期するべき場合です。以下の例を見てください。



extern int global; [By Value] CPPTEST_ON_CALL("foo").Arg("param1").Assign(global); [By Reference] CPPTEST_ON_CALL("foo").Arg("param1").Assign(ByRef(global)); 

1 番目の例では、CPPTEST_ON_CALL 定義が処理されるときに、param1 に代入される値がコピーされます。変数 global の実際の値に対してどんな変更があっても、代入時には反映されません。

2 番目の例では、CPPTEST_ON_CALL 定義が処理されるときに、param1 に代入される値はコピーされません。その代わり、それに対する "参照" が (ポインターとして) 格納され、代入時に global の実際の値が取られます。

C モードと C++ モードとでは、スタブの振る舞い定義の値を指定するときに重要な違いがあります。C モードでは、型に固有の関数を使って必ず値の指定をラップしなければなりません。 例:



CPPTEST_ON_CALL("foo")->Arg("param2")->Assign()->Float(1.5);
CPPTEST_ON_CALL("foo")->Arg("param3")->Assign()->VoidPtr(ptr); 

すべてのラップ関数は、すべての単純型に対して提供されています。完全なリストについては 「スタブ API リファレンス」を参照してください。C++ モードでは、ラップ関数を使わずに値を提供できます。値の指定が必要なすべての状況で、一般的な “Value”関数を使用できます。これはすべての単純型についてオーバーロードされます。表記をより簡単にするために、オーバーロードされた "演算子-メソッド" は値を直接受け取ります。この例を以下に示します。



CPPTEST_ON_CALL("foo").Arg("param1").Assign().Value(1);
CPPTEST_ON_CALL("foo").Arg("param1").Assign().Value(1.77);
CPPTEST_ON_CALL("foo").If().Arg("p1").Greater().Value(1.77).Arg("p2").Assign(0); 

オーバーロードした “演算子” メソッドを使用した、より単純な表記:



CPPTEST_ON_CALL("foo").Arg("param1").Assign(1);
CPPTEST_ON_CALL("foo").Arg("param1").Assign(1.77);
CPPTEST_ON_CALL("foo"().Arg("p1").Greater(1.77).Arg("p2").Assign(0); 

以下のセクションでは、スタブ API の一般的な使用事例について説明します。

例 1: オリジナル関数を呼び出す

オリジナルの関数/メソッドをスタブ定義から呼び出すことができます (オリジナルの定義はテスト バイナリで利用可能なものとします)。オリジナル シンボルへの呼び出しはデフォルトで無効です。この機能を有効にするには、ゼロではない値を名前付き引数 __callOrig に代入します。機能を無効にするには、この引数にゼロを代入します。

オリジナル関数の呼び出しが有効なのにオリジナルの定義が存在しない場合、停止条件がない状態でスタブが再帰的に呼び出されます。これはスタック オーバーフロー エラーを引き起こします。

以下のシグニチャを持つ関数に対してスタブを設定するものとします。


int foo(int param1, int param2);

  1. オリジナル関数への呼び出しを有効にします。  
    [C++] CPPTEST_ON_CALL("foo").Arg("__callOrig").Assign(1);
    [C] CPPTEST_ON_CALL("foo")->Arg("__callOrig")->Assign()->Int(1);
  2. パラメーターの値に応じてオリジナル関数の呼び出しを有効にすることもできます。パラメーター param1 0 に設定した状態でスタブを呼び出した場合、オリジナル関数が呼び出されます。それ以外の場合にはオリジナル関数は呼び出されません。  
    [C++] CPPTEST_ON_CALL("foo").If().Arg("param1").Equal(0). Arg("__callOrig").Assign(1);
    [C] CPPTEST_ON_CALL("foo")->If()->Arg("param1")->Equal()->Int(0)-> Arg("__callOrig")->Assign()->Int(1);

例 2: スタブの戻り値を変更する

スタブから返される値を変更できます。C++test が生成するスタブには、この目的に特化した __return という名前付き引数があります。この引数に値を代入すると、スタブから返される値が変更されます。スタブの戻り値が変更されない場合、デフォルト値が返されます。

以下のシグニチャを持つ関数に対してスタブを設定するものとします。


int foo(int param1, int param2);

  1. すべてのスタブ呼び出しで整数値 5 を返すようにすることができます。  
    [C++] CPPTEST_ON_CALL("foo").Arg("__return").Assign(5);
    [C] CPPTEST_ON_CALL("foo")->Arg("__return").Assign()->Int(5);
  2. スタブ パラメーターの値に応じて戻り値を指定できます。以下の例は、パラメーター param1 が整数値 0 に等しい場合、スタブ呼び出しの戻り値として整数値 5 を返します。それ以外のすべてのケースでは、デフォルト値 (数値型の場合は 0) を返します。  
    [C++] CPPTEST_ON_CALL("foo").If().Arg("param1").Equal(0). Arg("__return").Assign(5); [C] CPPTEST_ON_CALL("foo")->If()->Arg("param1")->Equal()->Int(0)-> Arg("__return")->Assign()->Int(5);
  3. オリジナル関数を呼び出して戻り値を変更できます。以下の例は、オリジナル関数を呼び出して戻り値を整数値の 5 に変更します。  
    [C++] CPPTEST_ON_CALL("foo").Arg("__callOrig").Assign(1). Arg("__return").Assign(5); [C] CPPTEST_ON_CALL("foo")->Arg("__callOrig")->Assign()->Int(1)-> Arg("__return")->Assign()->Int(5);

例 3: スタブ呼び出しのパラメーター値をチェックする

定義済みの値に対してスタブ呼び出しパラメーターの値をテストすることができます。C++test が生成するスタブには、スタブ呼び出しパラメーターを表す専用の名前付き引数があります。スタブの振る舞い定義の引数名は、オリジナル関数の宣言で使用されている名前と同じです。

以下のシグニチャを持つ関数に対してスタブを設定するものとします。

int foo(int param1, int param2);

  1. スタブ呼び出しパラメーター param10 に等しいかどうかをテストします。等しくない場合、指定のメッセージを出してテストは失敗します。  
    [C++] CPPTEST_ON_CALL("foo").If().Arg("param1").NotEqual(0). Fail("Incorrect param value");
    [C] CPPTEST_ON_CALL("foo")->If()->Arg("param1")->NotEqual()->Int(0)->Fail("Incorrect param value");

例 4: スタブ呼び出しパラメーターの値を変更する

前の例と同じように、スタブ呼び出しパラメーターに値を代入することができます。通常、この処理を行うのはオリジナル関数/メソッドへの呼び出しが必要な場合です。

以下のシグニチャを持つ関数に対してスタブを設定するものとします。

int foo(int param1, int param2);

  1. スタブ呼び出しパラメーターに値を代入することができます。この例では、スタブ呼び出しパラメーター param1 に整数値 1 を代入します。  
    [C++] CPPTEST_ON_CALL("foo").Arg("param1").Assign(1);
    [C] CPPTEST_ON_CALL("foo")->Arg("param1")->Assign()->Int(1);
  2. 別のパラメーターに応じて、パラメーターに値を代入できます。この例では、param1 の値が整数値 0 に等しい場合、param2 に整数値 1 を代入します。  
    [C++] CPPTEST_ON_CALL("foo").If().Arg("param1").Equal(0). Arg("param2").Assign(1);
    [C] CPPTEST_ON_CALL("foo")->If()->Arg("param1")->Equal()->Int(0)-> Arg("param2")->Assign()->Int(1);


  • No labels