共用方式為


測試產生

在傳統的單元測試中,測試由多個項目組成:

以下為範例測試結構:

[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 需要建構物件時,對建構函式和 Factory 方法的呼叫會依需要自動新增至序列。

參數化單元測試

參數化單元測試 (PUT) 是採用參數的測試。 不同於傳統的單元測試,它們通常是 Closed 方法,PUT 會採取任何一組參數。 就這麼簡單嗎? 是 - IntelliTest 會在這裡嘗試產生 (最小的) 輸入集完全涵蓋測試接觸到的程式碼。

PUT 是使用 PexMethod 自訂屬性以類似 MSTest (或 NUnit、xUnit) 的方式定義。 PUT 是標記為 PexClass,以邏輯方式分組為類別的執行個體方法。 下列範例顯示的簡單 PUT,儲存在 MyPexTest 類別:

[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 類別。 在此情況下,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
{
   ...
}

先決條件

方法的前置條件會以方法能夠成功的條件表示。

通常,強制執行前置條件的方法是檢查參數以及物件狀態,並在違規時擲回 ArgumentExceptionInvalidOperationException

在 IntelliTest 中,參數化單元測試的前置條件會使用 PexAssume 表示。

後置條件

方法的後置條件會以方法執行期間和之後應該保留的條件表示,假設其前置條件一開始有效。

通常,強制執行後置條件的方法是呼叫 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
        }
    }
}

進一步閱讀

有什麼建議嗎?

開發人員社群上張貼您的意見與功能建議。