動的なシンボリック実行を使用する入力生成
IntelliTest は、プログラムの分岐条件を分析して、パラメーター化された単体テストの入力を生成します。 テスト入力は、プログラムの新しい分岐動作をトリガーできるかどうかに応じて、選択されます。 分析はインクリメンタル処理です。 仮テスト入力パラメーター I
に対して、述語 q: I -> {true, false}
が絞り込まれます。 q
は、IntelliTest で既に観察されている動作セットを表します。 最初は、まだ何も観測されていないため、q := false
となります。
ループの手順は次のとおりです。
IntelliTest により、制約ソルバーを使用して、
q(i)=false
のように入力i
が決定されます。 構造により、入力i
では新しい実行パスが使用されます。 最初は、これが意味するのは、i
が何らかの入力になることです。実行パスが見つけられていないためです。IntelliTest により、選択された入力
i
でテストが実行され、テストの実行とテスト対象のプログラムが監視されます。実行中、プログラムは、プログラムのすべての条件付き分岐で決定される特定のパスを使用します。 実行を決定するすべての条件セットはパス条件と呼ばれ、仮入力パラメーターで述語
p: I -> {true, false}
として書き込まれます。 IntelliTest は、この述語の表現を計算します。IntelliTest で
q := (q or p)
が設定されます。 つまり、p
で表されるパスが示されたことを記録します。手順 1. に進みます。
IntelliTest の制約ソルバーは、.NET プログラムで表示される可能性のあるすべての型の値を処理できます。
IntelliTest は、示された前提事項に違反する入力をフィルター処理で除外します。
即時入力 (パラメーター化された単体テストに対する引数) を除き、テストでは PexChoose 静的クラスからさらに入力値を取得できます。 選択内容によって、パラメーター化されたモックの動作も決まります。
制約ソルバー
IntelliTest は制約ソルバーを使用して、テストの関連する入力値と、テスト対象のプログラムを決定します。
IntelliTest は Z3 制約ソルバーを使用します。
動的コード カバレッジ
ランタイム監視の副作用として、IntelliTest は動的コード カバレッジ データを収集します。 これは動的と呼ばれます。IntelliTest は実行されたコードのみを認識するため、他のカバレッジ ツールで通常行われるようにカバレッジに絶対値を指定できません。
たとえば、IntelliTest が動的カバレッジを 5/10 基本ブロックとして報告した場合、10 個のうち 5 個のブロックがカバーされたことを意味します。この場合、分析でこれまでに到達したすべてのメソッド (テスト対象のアセンブリに存在するすべてのメソッドではない) のブロックの総数は 10 です。 その後の分析で、さらに到達可能なメソッドが検出されたときに、分子 (この例では 5) と分母 (10) の両方が増える可能性があります。
整数と浮動小数点数
IntelliTest の制約ソルバーは、テストとテスト対象のプログラムに対して異なる実行パスをトリガーするために、byte、int、float などのプリミティブ型のテスト入力値を決定します。
オブジェクト
IntelliTest で既存の .NET クラスのインスタンスを作成できます。また、特定のインターフェイスを実装し、用途に応じて異なる方法で動作するモック オブジェクトの作成を IntelliTest を使用して自動で行うこともできます。
既存クラスのインスタンス化
何が問題なのでしょうか。
IntelliTest は、テストとテスト対象のプログラムを実行するときに実行された命令を監視します。 特に、フィールドへのすべてのアクセスを監視します。 その後、制約ソルバーを使用して、オブジェクトとそのフィールド値を含む、新しいテスト入力を決定し、テストとテスト対象のプログラムが他の適切な方法で動作するようにします。
つまり、IntelliTest は、特定の型のオブジェクトを作成し、そのフィールド値を設定する必要があります。 クラスが表示され、既定のコンストラクターが表示される場合、IntelliTest はそのクラスのインスタンスを作成できます。 クラスのすべてのフィールドが表示される場合、IntelliTest で自動的にフィールドを設定できます。
型が表示されない場合や、フィールドが表示されない場合、IntelliTest のみでオブジェクトを作成して、適切な状態にし、最大のコード カバレッジを実現することはできません。 IntelliTest の場合はリフレクションを使用して、任意の方法でインスタンスを作成して初期化することが可能ですが、通常、これは望ましくありません。オブジェクトが、通常のプログラム実行時には発生することのない状態になる可能性があるためです。 代わりに、IntelliTest はユーザーからのヒントに依存します。
視程
.NET には、詳細な可視性モデルがあります。型、メソッド、フィールド、その他のメンバーをプライベート、パブリック、内部などにすることができます。
IntelliTest は、テストを生成する際に、生成されたテストのコンテキスト内からの .NET 可視性ルールに関して正当なアクション (コンストラクター、メソッドの呼び出しや、フィールドの設定など) のみを実行しようとします。
ルールは次のようになります。
内部メンバーの可視性
- IntelliTest は、生成されたテストで、外部の PexClass に表示された内部メンバーにアクセスできると見なします。 .NET の InternalsVisibleToAttribute では、他のアセンブリに内部メンバーの可視性を拡張します。
PexClass のプライベートおよびファミリ (C# で保護されている) メンバーの可視性
パブリック メンバーの可視性
- IntelliTest は、PexClass のコンテキストで表示される、エクスポートされたすべてのメンバーを使用できると見なします。
パラメーター化されたモック
インターフェイス型のパラメーターを持つメソッドはどのようにテストするのですか? 非シール クラスについてはどうですか? IntelliTest は、このメソッドが呼び出されたときに、後でどの実装が使用されるかを認識できません。 おそらく、テスト時に使用できる実際の実装もありません。
従来の答えは、明示的な動作でモック オブジェクトを使用することです。
モック オブジェクトはインターフェイスを実装 (または、非シール クラスを拡張) します。 これは実際の実装ではなく、モック オブジェクトを使用するテストの実行を許可する単なるショートカットを表します。 その動作は、使用される各テスト ケースの一部として手動で定義します。 モック オブジェクトとその予期される動作の定義を容易にするツールは多数あります。それでも、この動作は手動で定義する必要があります。
モック オブジェクトのハード コーディングされた値の代わりに、IntelliTest は値を生成できます。 パラメーター化された単体テストを有効にする場合と同じように、IntelliTest ではパラメーター化されたモックも有効にされます。
パラメーター化されたモックには次の 2 つの異なる実行モードがあります。
- 選択: コードを探索する場合、パラメーター化されたモックは追加のテスト入力のソースであり、IntelliTest は対象の値を選択しようとします。
- 再生: 以前に生成されたテストを実行する場合、パラメーター化されたモックはスタブのように (つまり、定義されたとおりに) 動作します。
パラメーター化されたモックの値を取得するには、PexChoose を使用します。
構造体
IntelliTest の構造体の値に関する推論は、オブジェクトの処理方法に似ています。
配列と文字列
IntelliTest は、テストとテスト対象のプログラムを実行するときに実行された命令を監視します。 特に、プログラムが文字列または配列の長さ (および多次元配列の下限と長さ) に依存する場合に監視します。 また、プログラムが文字列または配列のさまざまな要素を使用する方法を監視します。 その後、制約ソルバーを使用して、テストとテスト対象のプログラムが適切に動作するように長さと要素の値を決定します。
IntelliTest は、適切なプログラムの動作をトリガーするのに必要な配列と文字列のサイズを最小化しようとします。
追加入力の取得
PexChoose 静的クラスを使用して、テストへの追加入力を取得することができ、パラメーター化されたモックを実装できます。
フィードバックが欲しい場合
ご意見や機能に関するご要望を開発者コミュニティで投稿してください。