共用方式為


單元測試基本概念

本主題說明 Visual Studio 測試總管描述文字和執行單元測試的基本概念。 它包含以下各節:

單元測試概觀

  • 快速啟動

MyBank 方案範例

建立單元測試專案。

撰寫您的測試。

在測試總管執行測試

  • 測試總管工具列的執行及檢視測試

  • 在每一個組建之後執行測試

  • 篩選和分組測試清單

偵錯單元測試

針對單元測試的其他工具。

  • 產生測試的應用程式程式碼

  • 針對使用資料驅動型測試的方法來做數個測試。

  • 分析單元測試程式碼涵蓋範圍

  • 使用 Microsoft Fakes 來隔離單元測試方法

單元測試概觀

Visual Studio 測試總管是設計為支援合併在他們的軟體開發實務的 單元測試 的開發人員和小組。 單元測試可協助您驗證確定程式的正確性,使應用程式碼如預期般運作。 在單元測試中,分析您的程式功能以找出可以測試做為個別 單位的分隔可測試的行為。 您可以使用單元測試架構 建立那些行為測試和報告測試的結果。

在您的軟體開發工作時,測試單元的整數部分具有最大的影響。 當您撰寫函式或應用程式程式碼的其他區塊,您會建立驗證程式碼,在標準、界限和無效的情形下,輸入資料並確認程式碼的所有明確或隱含假設的單元測試。 在稱為測試 導向開發的軟體開發作法中,您可以在撰寫程式碼之前建立單元測試,因此您可以使用單元測試做為設計功能的文件和功能規格。

測試總管提供富彈性且有效的方法執行單元測試並檢視其在 Visual Studio 的結果。 Visual Studio 安裝Microsoft 單元測試架構的管理以及原始碼。 測試總管也可以實作測試總管附加元件介面的第三方,來開啟來源單元測試架構。 您可以透過 Visual Studio 擴充管理員和 Visual Studio Gallery 加入許多這些框架。 請參閱 HOW TO:安裝協力廠商單元測試架構

測試總管檢視可以顯示所有測試,或是已執行、失敗、未執行、或是尚未執行的測試。 您可以篩選所有檢視的測試,以符合搜尋方塊中輸入的文字在全域層級或藉由選取其中一個預先定義的篩選條件。 您可以隨時執行測試的任何範圍。 當您使用 Visual Studio Ultimate時,您可以自動執行測試每個組建。 測試回合的結果會顯示在成功或失敗列上在 [檔案總管] 視窗的頂端。 當您選取測試時,測試方法結果的詳細資料隨即顯示。

Hh694602.collapse_all(zh-tw,VS.110).gif快速啟動

如需採用您直接輸入程式碼撰寫單元測試的簡介,請參閱下列其中一個主題:

MyBank 方案範例

在本主題中,我們使用例如呼叫 MyBank 的虛擬應用程式的開發。 您不需要依照本主題中說明的實際程式碼。 測試方法以 C# 撰寫,而且將使用測試架構的 Microsoft 單位為 Managed 程式碼,不過其概念可輕鬆地移動至其他語言和架構。

MyBank 方案

我們設計的第一次嘗試 MyBank 應用程式,其包含在這個區塊表示一個帳戶及其交易的帳戶元件和表示功能彙總 (Aggregate) 及處理個人帳戶的資料庫元件。

我們會建立包含兩個專案的 MyBank 方案:

  • Accounts

  • BankDb

我們將在設計 Accounts 專案中,第一次嘗試包含類別保存有關帳戶、指定任何帳戶通用功能,例如放置和提領資產從這個帳戶的介面和從表示檢查帳戶的介面都衍生自類別的基本資訊。 首先建立下列原始程式檔開頭帳戶專案:

  • AccountInfo.cs 定義帳戶的基本資訊。

  • IAccount.cs 定義一個帳戶的標準 IAccount介面,包括方法放置和提領現金帳戶的屬性及擷取帳戶餘額。

  • CheckingAccount.cs 包含實作檢查帳戶的 IAccounts 介面的 CheckingAccount 類別。

我們從經驗知道,檢查帳戶必須注意的一件事,確定提領的數量小於帳戶的餘額。 所以我們覆寫 CheckingAccount 的 IAccount.Withdaw 方法以檢查這個情況的方法。 產生的方法將如下所示:

public void Withdraw(double amount)
{
    if(m_balance >= amount)
    {
        m_balance -= amount;
    }
    else
    {
        throw new ArgumentException(amount, "Withdrawal exceeds balance!")
    }
}

現在我們已經有一些程式碼,測試的時間到了。

建立單元測試專案。

單元測試專案通常反映單一程式碼專案的結構。 在 MyBank 範例中,您將 AccountsTests BankDbTests 和 MyBanks 兩個單元測試專案加入至方案中。 測試專案名稱是選擇性的,不過以標準命名慣例是不錯的作法。

若要將單元測試專案加入至方案:

  1. 在 [檔案] 功能表上,選擇 [新增] 然後選取 [專案] 鍵盤 (CTRL + SHIFT + N)。

  2. [新增專案] 對話方塊中,展開 [已安裝的] 節點,選取您想要針對測試專案所使用的語言,然後選取 [測試]。

  3. 若要使用其中一個 Microsoft 單元測試架構,在專案範本清單中選取 [單元測試專案] 。 否則,請選取您要使用單元測試架構的專案範本。 若要測試我們的範例 Accounts 專案,您可以將專案命名為 AccountsTests。

    警告

    並非所有協力廠商和開啟來源單元測試架構都有提供 Visual Studio 專案範本。如需建立專案的詳細資訊,請參閱文件。

  4. 在單元測試專案中,請在我們的範例為帳戶專案中加入程式碼專案的參考進行測試。

    若要建立與程式碼專案的參考:

    1. 在 [方案總管] 中選取專案。

    2. 在 [專案] 功能表上,請選擇並按一下 [加入參考]。

    3. 在參考管理員對話方塊中,開啟 [方案] 節點並選取 [專案]。 選取程式碼專案名稱並關閉對話方塊。

每個單元測試專案包含反映類別與在程式碼專案中的類別。 在範例中, AccountsTests 專案將會包含下列類別:

  • AccountInfoTests 類別在 BankAccount 專案包含 AccountInfo 類別的單元測試方法。

  • CheckingAccountTests 類別包含 CheckingAccount 類別的單元測試方法。

撰寫您的測試。

您使用的單元測試架構和 Visual Studio IntelliSense 會引導您來建置程式碼專案的單元測試。 若要在測試總管中執行,大部分架構需要您加入特定屬性識別單元測試方法。 這個架構也提供一種是透過 Assert 陳述式或方法屬性的方式,來設定表示測試方法是否通過或失敗。 其他屬性會識別類別初始化,並且在類別終結之前,執行每個測試方法的每個測試方法和反組譯方法的選擇性設定方法。

AAA (排列,動作,判斷提示) 模式是一種常見的撰寫方式,來對單元測試來進行測試。

  • 測試方法的 排列 部分初始化物件,設定傳遞至待測方法的資料值。

  • 動作在排列的參數之測試中呼叫方法。

  • 判斷提示 部分驗證方法的動作待測如預期般運作。

若要測試我們的範例 CheckingAccount.Withdraw 方法,可以透過兩個測試: 驗證方法的標準行為和驗證撤退詳細的另一個則會失敗。 在CheckingAccountTests 類別中,我們加入下列方法。

[TestMethod]
public void Withdraw_ValidAmount_ChangesBalance()
{
    // arrange
    double currentBalance = 10.0;
    double withdrawal = 1.0;
    double expected = 9.0;
    var account = new CheckingAccount("JohnDoe", currentBalance);
    // act
    account.Withdraw(withdrawal);
    double actual = account.Balance;
    // assert
    Assert.AreEqual(expected, actual);
}

[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void Withdraw_AmountMoreThanBalance_Throws()
{
    // arrange
    var account = new CheckingAccount("John Doe", 10.0);
    // act
    account.Withdraw(1.0);
    // assert is handled by the ExcpectedException
}

請注意 Withdraw_ValidAmount_ChangesBalance 使用明確 Assert 陳述式判斷測試方法是否通過或失敗,而 Withdraw_AmountMoreThanBalance_Throws ExpectedException ,使用屬性判斷測試方法是否成功。 在封面下,單元測試架構是以 Try/Catch 陳述式的方法包裝測試。 在許多情況下,如果偵測到例外狀況,測試方法會失敗,且例外狀況會被忽略。 當指定的例外狀況發生時, ExpectedException 屬性會使測試方法回傳。

如需 Microsoft 單元測試架構的詳細資訊,請參閱下列其中一個主題:

在測試總管執行測試

當您建立測試專案時,測試隨即出現在測試總管。 如果測試總管不可見,請選擇 Visual Studio 功能表上的 [測試][Windows],然後選取 [測試總管]。

單元測試總管

當您執行、寫入、重新執行測試時,測試總管會顯示預設檢視結果。 [失敗的測試] 的群組中, [通過的測試]、 [尚未執行的測試] 和 [未執行的測試]。 您可以選取群組標題,開啟該群組中顯示所有其所測試的檢視。

Hh694602.collapse_all(zh-tw,VS.110).gif測試總管工具列的執行及檢視測試

測試總管工具列會協助您探索組織和執行測試。

從 [測試總管] 的工具列執行測試

您可以選擇 [全部執行] 執行所有測試,或選取 [執行] 選取測試的子集執行。 在您執行一組測試之後,測試回合的摘要會出現在測試總管視窗底部。 選取測試並下方窗格中的測試詳細資料。 從內容功能表 (鍵盤 F12 [開啟測試] :) 顯示選取之測試的原始程式碼。

Hh694602.collapse_all(zh-tw,VS.110).gif在每一個組建之後執行測試

警告

在每一個組建之後執行單元測試 只在Visual Studio Ultimate 被支援。

建置後執行

若要執行單元測試,則在每個本機組建中選取標準功能表之後的 [測試] ,再選取測試總管工具列上的 [建置之後執行測試] 。

Hh694602.collapse_all(zh-tw,VS.110).gif篩選和分組測試清單

當有大量測試時,您可以輸入測試總管搜尋方塊中所指定的字串篩選清單。 您可以從篩選條件清單中選取一個或多個限制您的篩選事件。

搜尋篩選條件分類

[測試總管] 的 [群組] 按鈕

若要依分類群組測試,請選取 [群組依據] 按鈕。

如需詳細資訊,請參閱使用測試總管執行單元測試

偵錯單元測試

您可以使用測試總管啟動測試的偵錯工作階段。 逐步執行使用 Visual Studio 偵錯工具的程式碼會反覆的在單元測試和專案之間進行測試。 若要啟動偵錯:

  1. 在 Visual Studio 編輯器裡,請在您要偵錯的一或多個測試方法上設定中斷點。

    注意事項注意事項

    由於測試方法可以任何順序執行,請在您要偵錯的所有測試方法中設定中斷點。

  2. 在測試總管中選取測試方法,然後從捷徑功能表選取 [偵測選取的測試] 。

如需除錯工具的詳細資訊,請參閱Visual Studio 偵錯

針對單元測試的其他工具。

Hh694602.collapse_all(zh-tw,VS.110).gif產生測試的應用程式程式碼

如果您正在撰寫自己的測試,則在撰寫專案之前,您可以使用 IntelliSense 來產生類別和方法在您的專案。 撰寫陳述式在呼叫類別的或方法中產生,並開啟 IntelliSense 功能表在呼叫中執行的測試方法。 如果呼叫新類別的建構函式,從功能表選擇 [產生新的型別] 並遵循精靈將類別在程式碼專案中。 如果呼叫這個方法,從 IntelliSense 功能表選擇 [產生新方法] 。

[產生方法 Stub] Intellisense 功能表

Hh694602.collapse_all(zh-tw,VS.110).gif針對使用資料驅動型測試的方法來做數個測試。

注意事項注意事項

這些程序只適用於您撰寫 Microsoft 單元測試架構為管理程式碼的測試方法。如果使用不同的架構,請查閱同等功能的文件框架。

資料驅動型測試方法 可讓您驗證值範圍在單一單元測試方法。 若要建立資料驅動單元測試方法,請裝飾與指定資料來源和資料表包含變數值要測試的 DataSource 屬性方法。 使用 TestContext.DataRow[ColumnName] 索引子,在方法主體裡將您所指派的值指派給變數。

例如,假設我們將不必要的方法加入至名為的 AddIntegerHelperCheckingAccount 類別。 AddIntegerHelper 加入兩個整數。

若要建立 AddIntegerHelper 方法的資料驅動型測試,我們會先建立名為 AccountsTest.accdb 和名為 AddIntegerHelperData之資料表中的 Access 資料庫。 AddIntegerHelperData 表定義資料行指定加法,是資料行的第一個和第二個運算元所指定預期的結果。 我們以適當值填入一些資料列。

    [DataSource(
        @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Projects\MyBank\TestData\AccountsTest.accdb", 
        "AddIntegerHelperData"
    )]
    [TestMethod()]
    public void AddIntegerHelper_DataDrivenValues_AllShouldPass()
    {
        var target = new CheckingAccount();
        int x = Convert.ToInt32(TestContext.DataRow["FirstNumber"]);
        int y = Convert.ToInt32(TestContext.DataRow["SecondNumber"]); 
        int expected = Convert.ToInt32(TestContext.DataRow["Sum"]);
        int actual = target.AddIntegerHelper(x, y);
        Assert.AreEqual(expected, actual);
    }

每一個資料表中的屬性方法都會執行一次。 如果有任何反覆項目失敗,測試總管會回報方法測試失敗。 測試結果的詳細資料會顯示在每個資料列的成功或失敗狀態的方法窗格上。

如需詳細資訊,請參閱如何:建立資料驅動型單元測試

Hh694602.collapse_all(zh-tw,VS.110).gif分析單元測試程式碼涵蓋範圍

注意事項注意事項

單元測試之程式碼涵蓋範圍能以原生方式管理單元測試架構,與所執行的語言和所有單元測試架構。

您可以以您的單元測試實際測試數量您的產品代碼,並使用 Visual Studio 程式碼涵蓋範圍工具。 您可以執行程式碼涵蓋範圍所選取之測試或在方案中的所有測試。 程式碼涵蓋範圍結果視窗會顯示由行列、函式、類別、命名空間和模組產品的程式碼區塊百分比。

執行測試方法的程式碼涵蓋範圍中的方案,

  1. 選取 Visual Studio 功能表上的 [測試] 然後選取 [分析程式碼涵蓋範圍]。

  2. 選取其中一個命令:

    1. [選取的測試] 執行您在測試總管選取的測試方法。

    2. [所有測試] 執行方案中所有的測試方法。

涵蓋範圍結果會出現在 [程式碼涵蓋範圍結果] 視窗。

程式碼涵蓋範圍結果

如需詳細資訊,請參閱使用程式碼涵蓋範圍來決定所測試的程式碼數量

Hh694602.collapse_all(zh-tw,VS.110).gif使用 Microsoft Fakes 來隔離單元測試方法

注意事項注意事項

Microsoft 偽造範例僅適用於 Visual Studio Ultimate。Microsoft 偽造範例只能搭配您撰寫使用單元測試架構為 Managed 程式碼的測試方法。

問題

焦點放在驗證函式的內部程式碼,其單元測試方法有時會很難覆寫外部相依性的測試呼叫函式底下。 例如, CheckingAccount 範例類別中的方法可能應該呼叫 BankDb 主要元件來更新資料庫。 我們可以重構 CheckingAccount 類別如下所示:

class CheckingAccount : IAccount
{
    public CheckingAccount(customerName, double startingBalance, IBankDb bankDb)
    {
        m_bankDb = bankDb;
        // set up account
    }

    public void Withdraw(double amount)
    {
        if(m_balance >= amount)
        {
            m_balance = m_MyBankDb.Withdraw(m_accountInfo.ID, amount);
        }
        else
        {
            throw new ArgumentException(amount, "Withdrawal exceeds balance!")
        }
    }

    private IBankDb m_bankDb = null;
    // ...

這個單元測試方法 CheckingAccount.Withdraw 現在會因這個呼叫所造成錯誤。 m_bankDb.Withdraw。 資料庫或網路連接可能會遺失,或著資料庫中的使用權限可能會有錯誤。 在 m_bankDB.Withdraw 呼叫的失敗造成測試失敗,而沒有與其內部程式碼相關的原因。

Microsoft 偽造範例方案

Microsoft 偽造建立包含類別和方法,其可以用來在單元測試方法的類別以產生相依性的組件。 在產生的偽造範例模組的替代類別宣告的方法裡,委派每個公用方法的目標元件。 在測試方法中,您可實作委派建立相依性呼叫的實際行為在您要測試的方法。

在範例中,我們可以建立 BankDb 專案的偽造的組件,然後使用由偽造範例產生的組件,並且從介面衍生 IBankDb 取消互動所造成的不確定性與資料庫的 StubIBankDb 類別。 Withdraw_ValidAmount_ChangesBalance 測試方法的修改版本則如下所示:

[TestMethod]
public void Withdraw_ValidAmount_ChangesBalance()
{
    // arrange
    double currentBalance = 10.0;
    double withdrawal = 1.0;
    double expected = 9.0;

    // set up the Fakes object and delegate
    var stubBankDb = new MyBank.Stubs.StubIBankDb();
    stubBankDb.WithdrawDoubleDouble = (id, amount) => { return 9.0; }
    var account = new CheckingAccount("JohnDoe", currentBalance, stubBankDb);

    // act
    account.Withdraw(withdrawal);
    double actual = account.Balance;

    // assert
    Assert.AreEqual(expected, actual);
}

在測試方法中的這一行:

stubBankDb.WithdrawDoubleDouble = (id, amount) => { return 9.0; }

您可以使用 lamba 運算式,實作 Withdraw 偽造的委派方法。 stubBankDb.Withdraw 方法呼叫委派會傳回指定的數量,讓測試方法順利驗證 Accounts 方法的行為。

更多關於 Microsoft 偽造範例

Microsoft 偽造使用兩種方法建立替代的類別:

  1. Stub 會從目標相依性類別產生子類別的替代類別。 Stub 方法可被用於目標類別的公用虛擬方法所替代。

  2. Shim 使用執行階段測試裝置並呼叫為目標方法,再呼叫為非虛擬方法的替代 Shim 方法。

在這兩種方法中,您可以使用呼叫所產生的委派至相依性方法,來指定您在測試方法想要的行為。

如需詳細資訊,請參閱使用 Microsoft Fakes 在測試期間隔離程式碼