這個(gè)測(cè)試方法除了[Test]特性之外還關(guān)聯(lián)了一個(gè)[ExpectedException]特性——這指出測(cè)試代碼希望拋出一個(gè)指定類型的異常;如果在執(zhí)行過(guò)程中沒(méi)有拋出這樣的一個(gè)異常——該測(cè)試將會(huì)失敗。編譯你的代碼并回到GUI。由于你編譯了你的測(cè)試代碼,GUI會(huì)變灰并重構(gòu)了測(cè)試樹(shù),好像這個(gè)測(cè)試還沒(méi)有被運(yùn)行過(guò)(GUI可以監(jiān)視測(cè)試程序集的變化,并在測(cè)試樹(shù)結(jié)構(gòu)發(fā)生變化時(shí)進(jìn)行更新——例如,添加了新的測(cè)試)。點(diǎn)擊“Run”按鈕——我們又一次得到了一個(gè)紅色的狀態(tài)條。我們得到了下面的失敗消息:“TransferWithInsufficentFunds: InsufficientFundsException was expected”。我們來(lái)再次修改Account的代碼,象下面這樣修改TransferFunds()方法:
public void TransferFunds(Account destination, float amount) {
destination.Deposit(amount);
if(balance - amount < minimumBalance)
throw new InsufficientFundsException();
Withdraw(amount);
}
編譯并運(yùn)行測(cè)試——綠了。成功!不過(guò)等等,看看我們剛寫(xiě)的代碼,我們會(huì)發(fā)現(xiàn)銀行在每一筆不成功的轉(zhuǎn)賬操作時(shí)都虧錢了。讓我們來(lái)寫(xiě)一個(gè)測(cè)試來(lái)確認(rèn)我們的猜測(cè)。添加這個(gè)測(cè)試方法:
[Test]
public void TransferWithInsufficientFundsAtomicity() {
Account source = new Account();
source.Deposit(200.00F);
Account destination = new Account();
destination.Deposit(150.00F);
try {
source.TransferFunds(destination, 300.00F);
}
catch(InsufficientFundsException expected) {
}
Assert.AreEqual(200.00F,source.Balance);
Assert.AreEqual(150.00F,destination.Balance);
}
我們測(cè)試了方法的交易屬性——是否所有的操作都成功了。編譯并運(yùn)行——紅條。是的,我們平白無(wú)故地?fù)p失了300塊錢——source賬戶有正確的余額150.00,但destination賬戶顯示:$450.00。我們?cè)撊绾涡薷?我們能夠只將小余額檢查的調(diào)用放到數(shù)據(jù)更新的前面么:
public void TransferFunds(Account destination, float amount) {
if(balance - amount < minimumBalance) {
throw new InsufficientFundsException();
}
destination.Deposit(amount);
Withdraw(amount);
}
如果Withdraw()方法拋出了另外一個(gè)異常呢?我們應(yīng)該在catch塊中執(zhí)行一個(gè)補(bǔ)救處理,還是依賴我們的交易管理器來(lái)重新裝載對(duì)象的狀態(tài)?某些時(shí)候我們必須回答這樣的問(wèn)題,但不是現(xiàn)在;可我們眼前如何應(yīng)付這個(gè)失敗的測(cè)試呢——刪除它?一個(gè)不錯(cuò)的方法是臨時(shí)忽略它在你的測(cè)試方法中添加下面的特性:
[Test]
[Ignore("Need to decide how to implement transaction management in the application")]
public void TransferWithInsufficientFundsAtomicity() {
// code is the same
}
編譯并運(yùn)行——黃條。單擊“Test Not Run”選項(xiàng)卡,你會(huì)看到bank.AccountTest.TransferWithInsufficientFundsAtomicity()連同這個(gè)測(cè)試被忽略的原因一起列在列表中。
看看我們的測(cè)試代碼,我們可以看到一些適宜的重構(gòu)。所有的方法共享一組公共的測(cè)試對(duì)象。讓我們來(lái)將這些初始化代碼放到一個(gè)setup方法中并在所有的測(cè)試中重用它們。我們的測(cè)試類的重構(gòu)版本像下面這樣:
namespace bank {
using System;
using NUnit.Framework;
[TestFixture]
public class AccountTest {
Account source;
Account destination;
[SetUp]
public void Init() {
source = new Account();
source.Deposit(200.00F);
destination = new Account();
destination.Deposit(150.00F);
}
[Test]
public void TransferFunds() {
source.TransferFunds(destination, 100.00f);
Assert.AreEqual(250.00F, destination.Balance);
Assert.AreEqual(100.00F, source.Balance);
}
[Test]
[ExpectedException(typeof(InsufficientFundsException))]
public void TransferWithInsufficientFunds() {
source.TransferFunds(destination, 300.00F);
}
[Test,
Ignore (
"Need to decide how to implement transaction management in the application"
)]
public void TransferWithInsufficientFundsAtomicity() {
try {
source.TransferFunds(destination, 300.00F);
}
catch(InsufficientFundsException expected) {
}
Assert.AreEqual(200.00F,source.Balance);
Assert.AreEqual(150.00F,destination.Balance);
}
}
}
注意這個(gè)初始化方法擁有通用的初始化代碼,它的返回值類型為void,沒(méi)有參數(shù),并且由[SetUp]特性標(biāo)記。編譯并運(yùn)行——同樣的黃條!
============全文完==========
如果你安裝了NUnit V2.1,可以在 開(kāi)始->程序->NUnit V2.1->QuickStart 處得到原文(英文版)。