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