本文是官方文檔的學習筆記,官方文檔在這裏。less
一、打開VS3013,隨便建一個解決方案,好比叫:LearnUnitTest,建一個類庫項目LearnUnitTest_Bank,該項目中添加一個BankAccount類,這個類及類中的方法就是咱們要測試的對象。ide
二、給LearnUnitTest添加一個測試項目:在解決方案名稱上右鍵=》添加=》新建項目=》VisualC#=》測試=》單元測試項目,項目名稱叫LearnUnitTest_BankTest,將LearnUnitTest_Bank添加爲LearnUnitTest_BankTest的引用項目,將測試項目LearnUnitTest_BankTest裏默認生成的類重命名爲BankAccountTest。函數
對於BankAccountTest類,類上有註解TestClass,方法上有註解TestMethod。能夠在這類文件裏添加其餘類和方法,供測試方法使用。單元測試
首個測試:學習
三、如今咱們測試BankAccount類的Debit方法,咱們預先肯定這次測試要檢查以下方面:測試
a、若是信用餘額(credit amount)比帳戶餘額大,該方法就拋異常ArgumentOutOfRangeExceptionspa
b、若是信用餘額小於0也拋異常3d
c、若是a和b都知足,該方法會從帳戶餘額裏減去amount(函數參數)code
注意:由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"); }
測試方法的要求:
必需要有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 }
注意這個方法: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); } // ...
(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); } }
(5)再次測試,再次重寫,再次分析
當咱們用不的參數再次運行測試方法Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange
的時候,會遇到下面一些問題:
一、若是咱們使用一個比balance大的debitAmount運行,產生的測試結果是所指望的。
二、若是使用了一個debitAmount運行,使得assert 斷言失敗了(好比在Debit方法的某一行返回了一個非指望的異常),也沒什麼問題,在本測試的情理之中。
三、若是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.") }
最終咱們讓測試代碼變得更增強健,但更重要的是,在這個過程當中,我也們也改善了被測試的代碼——這纔是測試的最終目的。
微軟接下來說的是測試驅動開發。連接以下: