テスト生成

従来の単体テストでは、テストは以下のいくつかの要素で構成されます。

テスト構造の例を以下に示します。

[Test]
void MyTest() {
    // data
    ArrayList a = new ArrayList();

    // method sequence
    a.Add(5);

    // assertions
    Assert.IsTrue(a.Count==1);
    Assert.AreEqual(a[0], 5);
}

IntelliTest は多くの場合、より一般的なパラメーター化された単体テストの関連引数値を自動的に決定できます。パラメーター化された単体テストは、メソッド呼び出しとアサートのシーケンスを提供します。

テスト ジェネレーター

IntelliTest はテスト ケースを生成します。実行するテストの下で実装のメソッド シーケンスを選択し、メソッドの入力を生成し、同時に派生データのアサートを確認します。

パラメーター化された単体テストは直接、その本体でメソッドのシーケンスを明言します。

IntelliTest がオブジェクトを構築する必要がある場合、必要に応じて、シーケンスにコンストラクターとファクトリ メソッドの呼び出しが自動的に追加されます。

パラメーター化された単体テスト

パラメーター化された単体テスト (PUT) は、パラメーターを受け取るテストです。 通常は排他的な手法である従来の単体テストとは異なり、PUT はあらゆるパラメーター セットを受け取ります。 そんなに簡単なのでしょうか。 はい。次に IntelliTest は、テストから到達できるコードを完全にカバーする (最小の) 入力セットを生成します。

PUT は、MSTest (または NUnit、xUnit) と同様に、PexMethod カスタム属性を利用して定義されます。 PUT は、PexClass でタグ付けされるクラスで論理的にグループ化されるインスタンス メソッドです。 次は MyPexTest クラスに保存されている単純な PUT の例です。

[PexMethod]
void ReplaceFirstChar(string target, char c) {

    string result = StringHelper.ReplaceFirstChar(target, c);

    Assert.AreEqual(result[0], c);
}

ReplaceFirstChar は、文字列の最初の文字を置換するメソッドです。

class StringHelper {
    static string ReplaceFirstChar(string target, char c) {
        if (target == null) throw new ArgumentNullException();
        if (target.Length == 0) throw new ArgumentOutOfRangeException();
        return c + target.Substring(1);
    }
}

このテストから、IntelliTest は、テストされるコードのたくさんの実行パスをカバーする PUT の入力を自動的に生成できます。 異なる実行パスをカバーする各入力が単体テストとして "シリアル化" されます。

[TestMethod, ExpectedException(typeof(ArgumentNullException))]
void ReplaceFirstChar0() {
    this.ReplaceFirstChar(null, 0);
}
...
[TestMethod]
void ReplaceFirstChar10() {
    this.ReplaceFirstChar("a", 'c');
}

ジェネリックなパラメーター化単体テスト

パラメーター化された単体テストはジェネリック メソッドにすることができます。 その場合、PexGenericArguments を利用し、メソッドのインスタンス化に使用する種類を指定する必要があります。

[PexClass]
public partial class ListTest {
    [PexMethod]
    [PexGenericArguments(typeof(int))]
    [PexGenericArguments(typeof(object))]
    public void AddItem<T>(List<T> list, T value)
    { ... }
}

例外を許可する

IntelliTest は、予想される例外と予想外の例外に例外を選別するさまざまな検証属性を提供します。

予想される例外の場合、ネガティブなテスト ケースが生成され、ExpectedException(typeof(xxx)) のような注釈が付けられます。予想外の例外の場合、失敗のテスト ケースが生成されます。

[PexMethod, PexAllowedException(typeof(ArgumentNullException))]
void SomeTest() {...}

検証コントロール:

内部型をテストする

IntelliTest は認識可能な内部型を "テスト" できます。 IntelliTest が型を認識するには、Visual Studio IntelliTest ウィザードを利用し、製品またはテスト製品に次の属性を追加します。

[assembly: InternalsVisibleTo("Microsoft.Pex, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]

前提事項とアサーション

前提事項とアサーションを利用し、テストの前提条件 (前提事項) と事後条件 (アサーション) を表現できます。 IntelliTest がパラメーター値のセットを生成し、コードを "調べる" とき、テストの前提事項に違反することがあります。 その場合、そのパスのテストは生成されず、メッセージなしで無視されます。

アサーションは、通常の単体テスト フレームワークでよく知られた概念です。IntelliTest は、サポートされている各テスト フレームワークにより提供される組み込み Assert クラスを既に "理解" しています。 ただし、ほとんどのフレームワークで Assume クラスは提供されません。 Assume クラスが提供されない場合、IntelliTest は PexAssume クラスを提供します。 既存のテスト フレームワークを使用しない場合、IntelliTest には PexAssert クラスも与えられます。

[PexMethod]
public void Test1(object o) {
    // precondition: o should not be null
    PexAssume.IsNotNull(o);

    ...
}

具体的には、null を利用しない前提事項をカスタム属性としてエンコードできます。

[PexMethod]
public void Test2([PexAssumeNotNull] object o)
// precondition: o should not be null
{
   ...
}

[Precondition](#preconditions-allownull-and-disallownull)

メソッドの前提条件は、メソッドが成功となるための条件を表します。

通常、パラメーターとオブジェクトの状態を確認し、違反がある場合、ArgumentException または InvalidOperationException をスローすることで前提条件が強制されます。

IntelliTest では、パラメーター化された単体テストの前提条件は PexAssume で表現されます。

[事後条件](#postconditions-maybenull-and-notnull)

メソッドの事後条件は、メソッドの実行中と実行後に当てはまらなければならない条件を表します。その前に前提条件が有効と見なされたものと想定されます。

通常、事後条件は Assert メソッドを呼び出すことで強制されます。

IntelliTest では、パラメーター化された単体テストの事後条件は PexAssert で表現されます。

テスト不合格

生成されたテスト ケースはどのような場合に不合格となりますか。

  1. 構成されたパス バウンド内で終了しない場合、[TestExcludePathBoundsExceeded] オプションが設定されていない限り、不合格として見なされます。

  2. PexAssumeFailedException がスローされた場合、テストは合格です。 ただし、[TestEmissionFilter][すべて] に設定されていない限り、通常はフィルターで除外されます。

  3. テストがアサーションに違反した場合、たとえば、単体テスト フレームワークのアサーション違反例外がスローされた場合、不合格です。

上記のいずれでも判断されない場合、例外がスローされない場合、または、例外がスローされない場合に限り、テストは合格です。 アサート違反は例外と同様に扱われます。

セットアップと破棄

テスト フレームワークとの統合の一環として、IntelliTest はセットアップと破棄のメソッドを検出し、実行できます。

using Microsoft.Pex.Framework;
using NUnit.Framework;

namespace MyTests
{
    [PexClass]
    [TestFixture]
    public partial class MyTestClass
    {
        [SetUp]
        public void Init()
        {
            // monitored
        }

        [PexMethod]
        public void MyTest(int i)
        {
        }

        [TearDown]
        public void Dispose()
        {
            // monitored
        }
    }
}

参考資料

フィードバックが欲しい場合

ご意見や機能に関するご要望を開発者コミュニティで投稿してください。