このセクションでは、単体テスト カバレッジを増加させるための方法について説明します。
このセクションの内容 :
カバレッジが低い原因
C++test のテスト カバレッジは、定義済みメトリクスを使って測定されます ( 「カバレッジ情報の参照」 を参照)。一般的に、「テスト カバレッジの向上」のためには、すべてのテスト カバレッジ メトリクスの増加を目指すべきです。これらのメトリクスは、このセクションで説明するテクニックに影響を受けますが、どのケースにおいても、テクニックの適用とカバレッジ メトリクスへの影響の間には単純な論理的な関係を見ることができます。したがって、説明を簡潔にするためにここでは行カバレッジに特化して考えます。
ほとんどの場合、テスト カバレッジの増加の問題は次の 3 種類の状況に帰着します。
- 条件の制御式にすべてのブランチを実行させる入力値をテストが活用していない。
- テスト対象の関数の制御式が、他の関数から返却される値に依存している。つまり、テスト実行中のプログラム/コードの状態に依存している。
- テスト対象コードのための適切なセットアップをテストが使用していないため、テストの実行によって例外が発生し、例外の時点で実行フローが中断する。
コードの構造によって、そのような制御式は、たとえば 1 つの関数に 1 つの if/else しかない簡単な式の場合もあれば、複雑な式の場合もあります。複雑な式とは、たとえばブランチの式と混合された関数呼び出しの返却である条件式のネスト ループ条件などです。
これらのシナリオを基に、ケースに応じて C+++test フレームワークで条件を制御するためのさまざまなテクニックがあります。
カバレッジを増加させるための一般的なテクニック
コード カバレッジを増加させるための一般的なテクニックは次のとおりです。
- 特定の入力値/事前条件を使用するテストを新規に作成する ( 「ユーザー定義テスト ケースの追加」を参照)
- 特定のコンストラクターまたはコンストラクターの呼び出しシーケンスを使って、目的の状態のオブジェクトを作成する ( 「ユーザー定義テスト ケースの追加」を参照)
- ユーザー定義スタブを使用する ( 「スタブの追加と変更」を参照)
- テスト ケース起動のスタブを使用する ( 「テスト ケースから起動されるスタブ」を参照)
テスト カバレッジを増加するには、次の操作を推奨します。
- 目的のスコープ (プロジェクトまたはファイル) のコード カバレッジを検証します。
- 目標レベルよりコード カバレッジが低い場合、カバレッジ結果を解析し、次の項目に基づいてファイルまたは関数をランク付けします。
- 最も低いコード カバレッジ
- テスト対象コードの参照と判断による、労力に対するカバレッジの増加という点に関しての考えうる ROI (投資利益率)
- ランク付けの順序で、すべての関数において、カバレッジをブロックするすべての制御式とその条件値について次の作業を行います。
- 条件が直接の関数パラメーターまたは関数のクラスのデータ メンバーである場合、テスト ケース エディターを使って、条件を満たす設定値を使用するテスト ケースを作成する。
- 条件が直接的な関数パラメーターの単純な関数または関数のクラスのデータ メンバーである場合、テスト ケース エディターを使って、条件を満たす設定値を使用するテスト ケースを作成する。
- メソッド呼び出しを介して複雑なオブジェクトに制御式が依存しているような場合、適切な状態の複雑なオブジェクトを作成する (下記の「複雑なオブジェクト」を参照)。
- カバレッジ ブロックの原因が例外である場合
- コードを検証して例外がスローされる原因を特定する。
- 不正な関数/テスト ケース パラメーター値 (NULL ポインターの間接参照など) が原因で例外がスローされている場合、正しい値を関数に渡すテスト ケースを作成/変更する。
- 特定のオブジェクトの状態が問題である場合、下記の「複雑なオブジェクト」を参照。
- 例外をスローする関数のユーザー スタブを作成する。
- 複雑なコード シーケンスによってテスト対象関数内で条件が計算される場合、次の関数に続く。
テスト駆動スタブが適しているのは通常、事前条件またはパラメーターがない (またはほとんどない) 関数、あるいは UI とのやり取りをカプセル化してユーザー アクションを表す値を返却する関数です。そのような関数は、たとえば GUIWidget::whichButtonWasPressed() のような関数です。
条件が関数の戻り値である場合、シンボル代替の優先順序は a) オリジナル関数 b) ユーザー スタブ c) 自動スタブ です。
ユーザー スタブ
通常、次のいずれかの値を返すようにユーザー スタブ を作成します。
- 呼び出されるたびに同じ値を返却する
- 呼び出されるたびに違う値を返却する
- テスト ケースの名前 (テスト駆動スタブ) によって異なる値を返却する
複雑なオブジェクト
複雑なオブジェクトの状態に条件が依存する場合 (例:リスト メンバーを操作する関数、たとえば List::containsElement(Element&) など)、オブジェクトは、機能テストへの適切な事前条件として適切な状態に設定される必要があります。この場合、重要なのは次の 2 点です。
- オブジェクトの望ましい状態は何か ?
- どうすればこの状態を得られるか?
オブジェクトの望ましい状態は、次の操作によって得ることができます。
- メンバーワイズなオブジェクトの初期化を使用します。 (これは単純なクラスにだけ適しています)。C++test のインストゥルメント機能によって、オブジェクトのすべての private データ メンバーにテスト ケース本体から直接アクセスできます。したがって、特定のテスト ケースの実行に影響するデータ メンバーへの直接代入を使用できます。
- 特定の引数セットを持つパラメータライズド コンストラクターを使って、テスト オブジェクトを作成します。
- テスト スイートの setUp メソッドで適用される特定の初期化呼び出しシーケンスを使用します。これは特に、重要な初期化をテスト オブジェクトが常に必要とする場合に有効です。setUp メソッドを使用すると、初期化シーケンスを一度に指定して、テスト スイート中のすべてのテスト ケースに自動的に適用できます。
- テスト オブジェクト ファクトリを使用します。ファクトリ クラス メソッドを使って、既知の状態のテスト オブジェクトを用意します。