VS2013 單元測試(使用VS2013自帶的單元測試)


本文是官方文檔的學習筆記,官方文檔在這里

1、打開VS3013,隨便建一個解決方案,比如叫:LearnUnitTest,建一個類庫項目LearnUnitTest_Bank,該項目中添加一個BankAccount類,這個類及類中的方法就是我們要測試的對象。

2、給LearnUnitTest添加一個測試項目:在解決方案名稱上右鍵=》添加=》新建項目=》VisualC#=》測試=》單元測試項目,項目名稱叫LearnUnitTest_BankTest,將LearnUnitTest_Bank添加為LearnUnitTest_BankTest的引用項目,將測試項目LearnUnitTest_BankTest里默認生成的類重命名為BankAccountTest。

對於BankAccountTest類,類上有注解TestClass,方法上有注解TestMethod。可以在這類文件里添加其他類和方法,供測試方法使用。

首個測試:

3、現在我們測試BankAccount類的Debit方法,我們預先確定此次測試要檢查如下方面:

  a、如果信用余額(credit amount)比賬戶余額大,該方法就拋異常ArgumentOutOfRangeException

  b、如果信用余額小於0也拋異常

  c、如果a和b都滿足,該方法會從賬戶余額里減去amount(函數參數)

  注意:由a、b、c可以看郵BankAccount類中的Debit方法最后一行應該是-=,而不是+=——當然了,這個是故意留下的bug,而不是微軟的失誤,就等着在這次測試中把它測出來,然后修正掉。

  

  在測試類里添加如下方法測試Debit方法:

  

// unit test code
[TestMethod]
public void Debit_WithValidAmount_UpdatesBalance()
{
    // arrange
    double beginningBalance = 11.99;
    double debitAmount = 4.55;
    double expected = 7.44;
    BankAccount account = new BankAccount("Mr. Bryan Walton", beginningBalance);

    // act
    account.Debit(debitAmount);

    // assert
    double actual = account.Balance;
    Assert.AreEqual(expected, actual, 0.001, "Account not debited correctly");
}
View Code

  測試方法的要求:

  必須要有TestMethod注解,返回類型為void,不能有參數。

經過測試,我們發現了bug,把+=改為-=即可。

使用單元測試改善代碼:

  依然是測試Debit,本次測試想完成以下意圖:

  a、如果credit amount(指的應該就是debit amount)比balance大,方法就拋ArgumentOutOfRangeException

  b、如果credit amount比0小,也拋ArgumentOutOfRangeException異常

(1)創建測試方法

首次嘗試創建一個測試方法來處理上述問題:

代碼:

//unit test method
[TestMethod]
[ExpectedException(typeof(ArgumentOutOfRangeException))]
public void Debit_WhenAmountIsLessThanZero_ShouldThrowArgumentOutOfRange()
{
    // arrange
    double beginningBalance = 11.99;
    double debitAmount = -100.00;
    BankAccount account = new BankAccount("Mr. Bryan Walton", beginningBalance);

    // act
    account.Debit(debitAmount);

    // assert is handled by ExpectedException
}
View Code

注意這個方法:Debit_WhenAmountIsLessThanZero_ShouldThrowArgumentOutOfRange,意思是:當debit amount小於0時,本次測試應該會導致被測試的方法拋出ArgumentOutOfRange異常,否則本次測試就失敗了,沒有達到期望,需要修改Debit代碼以達成本次測試期望——正所謂TDD開發。
我們使用了ExpectedExceptionAttribute特性來斷言期望的異常應當被拋出。除非方法拋出ArgumentOutOfRangeException異常,否則該特性就會導致測試失敗(要注意本次測試的意圖)。用正的和負的debitAmount運行這個測試,然后臨時把被測試的方法(Debit方法)修改一下:當demit amount小於0時拋出一個ApplicatinException。搗騰完這些,發現本次測試基本沒什么問題。

為了測試debit amount 大於balance的情形,我們做下面幾個操作:

  a、創建一個新的測試方法名叫    Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange

  b、從上一個測試方法

 Debit_WhenAmountIsLessThanZero_ShouldThrowArgumentOutOfRange

復制方法體到本測試方法

  c、把debitAmount設置為一個比balance大的值

(2)運行測試方法

用不同的debitAmount值運行Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange

 Debit_WhenAmountIsLessThanZero_ShouldThrowArgumentOutOfRange

然后運行三個測試,這樣我們最開始設定的三個cases都被覆蓋了。

(3)繼續分析

后面兩個測試方法Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange

 和Debit_WhenAmountIsLessThanZero_ShouldThrowArgumentOutOfRange

 有些問題:兩個測試運行的時候根據拋出的異常,你不知道是誰拋出的,靠ExpectedException特性做不到這件事。

可以這樣修改:

在類里定義兩個常量:

// class under test
public const string DebitAmountExceedsBalanceMessage = "Debit amount exceeds balance";
public const string DebitAmountLessThanZeroMessage = "Debit amount less than zero";

// method under test
// ...
    if (amount > m_balance)
    {
        throw new ArgumentOutOfRangeException("amount", amount, DebitAmountExceedsBalanceMessage);
    }

    if (amount < 0)
    {
        throw new ArgumentOutOfRangeException("amount", amount, DebitAmountLessThanZeroMessage);
    }
// ...
View Code

(4)重構測試方法

 首先,移除ExpectedException特性。取而代之的處理是:我們捕獲異常,來核實是在哪種條件下拋出的。

修改一下Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange 

方法:

[TestMethod]
public void Debit_WhenAmountIsGreaterThanBalance_ShouldThrowArgumentOutOfRange()
{
    // arrange
    double beginningBalance = 11.99;
    double debitAmount = 20.0;
    BankAccount account = new BankAccount("Mr. Bryan Walton", beginningBalance);\

    // act
    try
    {
        account.Debit(debitAmount);
    }
    catch (ArgumentOutOfRangeException e)
    {
        // assert
        StringAssert.Contains(e.Message, BankAccount. DebitAmountExceedsBalanceMessage);
    }
}
View Code


(5)再次測試,再次重寫,再次分析

當我們用不的參數再次運行測試方法Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange 

的時候,會遇到下面一些問題:

1、如果我們使用一個比balance大的debitAmount運行,產生的測試結果是所期望的。

2、如果使用了一個debitAmount運行,使得assert 斷言失敗了(比如在Debit方法的某一行返回了一個非期望的異常),也沒什么問題,在本測試的情理之中。

3、如果debitAmount是有效的(比0大比balance小)會發生什么呢?沒有異常拋出,斷言也不會失敗,測試方法通過了。——這不是我們想要的,注意我們此次的測試初衷:要么斷言成功,要么斷言失敗,如果壓根進入不了斷言代碼,只能說明測試方法寫的問題!

為了解決這個問題,我們在測試方法的最后一行加入一個Fail斷言,來處理沒有異常發生的情況:沒有異常發生,就說明此次測試沒有達到期望!

但是修改好再次運行,會發現如果所期望的異常被捕獲了,測試總會失敗。為了解決這個問題,我們在StringAssert之前加一個return。

最終我們的Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange 

方法如下:

[TestMethod]
public void Debit_WhenAmountIsGreaterThanBalance_ShouldThrowArgumentOutOfRange()
{
    // arrange
    double beginningBalance = 11.99;
    double debitAmount = 20.0;
    BankAccount account = new BankAccount("Mr. Bryan Walton", beginningBalance);\

    // act
    try
    {
        account.Debit(debitAmount);
    }
    catch (ArgumentOutOfRangeException e)
    {
        // assert
        StringAssert.Contains(e.Message, BankAccount. DebitAmountExceedsBalanceMessage);
        return;
    }
    Assert.Fail("No exception was thrown.")
}
View Code


最終我們讓測試代碼變得更加強健,但更重要的是,在這個過程中,我也們也改善了被測試的代碼——這才是測試的最終目的。

 

微軟接下來講的是測試驅動開發。鏈接如下:

測試驅動開發


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM