}
[TestMethod()]
[ExpectedException(typeof(ArgumentNullException))]
public void ConstructorTestBlank()
{
User target = new User(" ");
}
如果不修改類庫中的代碼,單元測試會報告這三個新的測試都失敗了。
小飛對代碼做了相應的修改。結果出了這樣的錯誤,見代碼清單11-5:
代碼清單11-5
Test method UserTest.UserTest.ConstructorTestBlank threw exception System.ArgumentException, but exception System. ArgumentNull- Exception was expected. Exception message: System.Argument- Exception: Value does not fall within the expected range.
大家定睛一看,原來小飛的Copy/Paste用了原來的ArgumentNullExcep- tion,而不是ArgumentException。
如果有人加了下面的代碼:
if (!m_email.Contains("@"))
{
throw new ArgumentException();
}
這時,代碼覆蓋測試就會報告代碼覆蓋率是85%左右。那還得加上新的單元測試以保證所有的代碼都得到了基本的測試。
二柱:現在我知道為什么有些軟件寫了好幾年都沒有發布了,敢情他們都忙著寫單元測試了。
阿超:也許因為他們沒有在一開始就寫單元測試,所以后來有很多小強要處理。很多調查顯示,在軟件開發后期發現的Bug,修復起來要花更多的時間。
蕓蕓:這對我們設計人員有什么用呢?好像都是一些細節的東西。
阿超:在我們寫規格說明書(specification)的時候,要越詳細越好,最好你的各項要求都可以表達成單元測試的一個測試用例。
蕓蕓:如果不能表示為一個單元測試呢?
二柱:那就是你寫得還不夠細。
小飛:我大膽地說一句。如果是一個人寫寫程序玩玩,單元測試似乎不那么重要。
二柱:你可以大膽地對你的女朋友說:“我們只是玩一玩……”看看效果如何。
阿超:如果玩一玩,什么都不太重要。如果你寫的模塊會有不同的人,在不同的時間使用,那你最好把你這一“單元”要做的事,以及它不能做的事,用單元測試清晰地表達出來。
2、好的單元測試的標準
下面我們講講怎樣才算一個好的單元測試。
單元測試應該準確、快速地保證程序基本模塊的正確性。下面是驗證單元測試好壞的一系列標準:
單元測試應該在最低的功能/參數上驗證程序的正確性。
單元測試應該測試程序中最基本的單元——如在C++/C#/Java 中的類,在此基礎上,可以測試一些系統中最基本的功能點(這些功能點由幾個基本類組成),從面向對象的設計原理出發,系統中最基本的功能點也應該由一個類及其方法來表現。單元測試要測試API中的每一個方法及每一個參數。
單元測試必須由最熟悉代碼的人(程序的作者)來寫。
代碼的作者最了解代碼的目的、特點和實現的局限性。所以,寫單元測試沒有比作者更適合的人選了。
問:如果我很忙,能不能讓別人代勞做單元測試?
答:如果忙到連單元測試都沒有時間做,那么你也沒有時間寫好這個功能。在一些極限編程的方法中,是可以考慮讓別人來做單元測試的,但是,程序的作者還是要對單元測試負責。
最好是在設計的時候就寫好單元測試,這樣單元測試就能體現API的語義,如果沒有單元測試,語義的準確性就不能得到保障,以后會產生歧義。
單元測試過后,機器狀態保持不變。
這樣就可以不斷地運行單元測試,如果單元測試創建了臨時的文件或目錄,應該在Teardown階段把這些臨時的文件或目錄刪除。
如果單元測試在數據庫中創建或修改了記錄,那么也許要刪除這些記錄,或者每一個單元測試使用一個新的數據庫,這樣可以保證單元測試不受以前單元測試實例的干擾。
單元測試要快(一個測試運行時間是幾秒鐘,而不是幾分鐘)。
快,才能保證效率。因為一個軟件中有幾十個基本模塊(類),每個模塊又有幾個方法,基本上我們要求一個類的測試要在幾秒鐘內完成。如果軟件有相互獨立的幾個層次,那么在測試組中可以分類,如數據庫層次、網絡通信層次、客戶邏輯層次和用戶界面層次,可以分類運行測試,比如只修改了“用戶界面”的代碼,則只需運行“用戶界面”的單元測試。
原文轉自:http://www.anti-gravitydesign.com