使用 Visual Studio 2005 Team System 進行單元測試并生成用于 Unit Test Framework 的源代碼
發布日期: 11/10/2005 | 更新日期: 11/10/2005
Scott Dockendorf
Telligent Systems, Inc.
適用于:
Microsoft Visual Studio 2005 Team System Beta 2
Team Architect & Team Test Editions
Microsoft Visual C# 2005
摘要: Scott 詳細介紹自動化單元測試的基本內容,以及由 Microsoft Visual Studio 2005 Team System 提供的 Unit Test Framework 中包含的代碼生成引擎。
本頁內容
簡介
隨著業務的革新和發展,運行它們的系統也需要進行更新。隨業務的發展、革新以及與合作伙伴、客戶和供應商的結合,這些系統將在復雜性方面持續擴增。
這種復雜性迫使 IT 的領導者們在開發過程中(即,在實現之前)確保質量。有一種方法可使開發人員減少進入 QA 環節的故障數量,即,針對自定義代碼嚴格執行自動化單元測試。在開發過程中強制使用自動化單元測試可為團隊成員提供有關如何使用自定義代碼的示例(這些示例易于使用并自行記錄)。
使用結構化、自動化單元測試面臨的挑戰之一是完成這些任務所需的代碼總數。(測試代碼需要使用大量代碼?。┐a生成的概念(簡單定義為“創建軟件的軟件”)正隨著時間的快速推移而逐漸深入到團隊 IT 開發之中。有些人認為代碼生成有助于縮短“推向市場”策略的時間,強制內部標準/協定,并促進開發過程。
Microsoft 認識到這一需要后提供了一個功能豐富、帶有下一代開發平臺 Visual Studio 2005 Team System (VSTS) 的代碼生成引擎。本文提供針對單元測試代碼生成的循序漸進的指導,并深入探討如何在用例中使用。
重新思考單元測試
請考慮以下情況:您負責為公司生成下一代系統,同時您是較大的開發團隊中的一員。您是 UI 開發人員,負責盡可能多地創建 Microsoft ASP.NET/Microsoft WinForms。您依賴“中間層”團隊完成其中間層組件 — 這些組件用于執行數據庫 CRUD (Create-Retrieve-Update-Delete) 以及與該系統中每個實體相關的業務規則。
經過幾周的 UI 開發,您完成了窗體并且收到了中間層開發人員打算向您提交其類庫的消息。表 1 提供一段對話示例,說明我們大多數人在開發過程中都會遇到的一些事情。
中間層:
|
“這些對象隨時供您使用 — 為此,只需獲取 OurSystemBL.dll 的最新版本?!?/p>
|
UI
:
|
“謝謝。您有供我們查看文檔嗎?”
|
中間層:
|
“哈哈!是的,當然有!我們花了很多時間編寫它!請查看 Design Document — 噢,請等一等,它還沒有完成……(不久之后即可完成?。?/p>
|
UI
:
|
“您使用 XML 文檔了嗎?”
|
中間層:
|
“在構造函數中,但許多方法都不使用?!?/p>
|
UI
:
|
“顯示如何創建、執行并刪除對象的示例代碼,怎么樣?”
|
中間層:
|
“我已經附加了一個示例 WinForms 應用程序(從我的工作區),它應該能夠提供一些您所需的內容……,雖然它不在 Microsoft Visual SourceSafe 中?!?/p>
|
在考慮如何進行這樣有趣的 項目之后,您打定了主意,決定檢驗中間層的單元測試套件。在深入鉆研該代碼之后,您注意到該窗體有兩個未標記的文本框,以及三個標記為 button1、button2 和 button3 的按鈕(幸運的話,它們將排列在窗體上)。接下來,在查看與這些按鈕相關的事件之后,您認識到這些代碼都未經注釋,并且數據變量都被命名為 x、y、z。如果幸運,您還會注意到 button1 和 button2 執行該對象的 Save() 方法,而 button3 執行 Delete() 方法。執行時,您會接收到很多 System.Exception 錯誤,這是因為遺漏了很多配置設置。
這顯然是一個特例,我希望多數開發團隊不要進行這一試驗,下面讓我們看一下該方案中“單元測試”遇到的問題:
? |
這種形式的單元測試代碼不是結構化的:代碼充斥到按鈕單擊事件中并且難以編譯。
|
? |
這種形式的單元測試代碼記錄得不太好。
|
? |
這種形式的單元測試并不基于“已知”為好或壞的數據 — 它完全依賴于輸入到那些未標記的文本框的內容。
? |
單元測試代碼不能自動重復,它基于輸入的代碼。
|
? |
單元測試代碼覆蓋是未知的 — 用數據指示實際測試的代碼量。
|
|
? |
實現的詳細信息不易于在團隊成員間進行傳播。
|
輸入自動化單元測試
xUnit 框架在 1998 年作為 eXtreme 編程的核心概念引入。它提出了一個有效的機制,有助于開發人員將結構化、有效且自動的單元測試添加常規開發活動中。從那以后,該框架演化為針對自動化單元測試框架的實際標準。
創建自動化單元測試的用例
簡單說,自動化單元測試是:
? |
結構化的。
|
? |
自行記錄的。
|
? |
自動且可重復的。
|
? |
基于已知數據。
|
? |
旨在測試積極和消極操作。
|
? |
非常適合跨不同計算機的測試實現。
|
? |
配置、實現和執行的示例。
|
xUnit 框架元素
表 2 分析 xUnit 框架以及對應于 Visual Studio 2005 Team System 的 Unit Testing Framework 等價物的基本概念。
測試
|
TestMethod
|
簡單說,這些是您的測試。測試預期結果的邏輯,并報告未取得結果(如果有)。請將它看作您的“方法”。
|
測試裝置
|
TestClass
|
針對大量測試的一個邏輯分組。請將它看作您的“類”。
|
測試套件
|
測試列表 **
|
針對大量測試裝置的一個邏輯分組。請將它看作您的“類庫”。
注不需要一個屬性。
|
測試運行器
|
VS 2005 VSTS Unit Testing Framework
|
GUI/Console 應用程序負責發現、執行和報告測試結果。Visual Studio 2005 Team System 將作為本文的測試運行器。
|
測試裝置示例
請考慮以下針對 BankAccount 類的類關系圖,以及一個示例測試裝置 (BankAccountTests.cs)。
圖
1. BankAccount
類
示例測試裝置: BankAccountTests.cs
using BankAccountDemo.Business;
using Microsoft.VisualStudio.QualityTools.UnitTesting.Framework;
namespace BankAccountDemo.Business.Tests
{
[TestClass()]
public class BankAccountTest
{
[TestInitialize()]
public void Initialize() {
}
[TestCleanup()]
public void Cleanup() {
}
[TestMethod()]
public void ConstructorTest() {
float currentBalance = 500;
BankAccount target = new BankAccount(currentBalance);
Assert.AreEqual(currentBalance, target.CurrentBalance,
"Balances are not equal upon creation");
}
[TestMethod()]
public void DepositMoneyTest() {
float currentBalance = 500;
BankAccount target = new BankAccount(currentBalance);
float depositAmount = 10;
target.DepositMoney(depositAmount);
Assert.IsTrue( (currentBalance + depositAmount) >
target.CurrentBalance,
"Deposit not applied correctly");
}
[TestMethod()]
public void MakePaymentTest() {
float currentBalance = 500;
BankAccount target = new BankAccount(currentBalance);
float paymentAmount = 250;
target.MakePayment(paymentAmount);
Assert.IsTrue(currentBalance - paymentAmount ==
target.CurrentBalance,
"Payment not applied correctly");
}
}
}
主單元測試概念 == 斷言
用于該形式單元測試的主要概念是,自動化單元測試是基于“斷言”的,即可定義為“事實或您相信為事實的內容”。從邏輯角度看,請考慮該語句“when I do {x}, I expect {y} as a result”。
這可以輕松地翻譯為代碼,方法是使用 Microsoft.VisualStudio.QualityTools.UnitTesting.Framework 命名空間中可用的三個“斷言”類中的任一個:Assert、StringAssert 和 CollectionAssert。主類 Assert 提供用于測試基礎條件語句的斷言。StringAssert 類自定義了在使用字符串變量時有用的斷言。同樣,CollectionAssert 類包括在使用對象集合時有用的斷言方法。
表 3 顯示可用于當前版本 Unit Testing Framework 的斷言。
AreEqual()
AreNotEqual()
AreNotSame()
AreSame()
EqualsTests()
Fail()
GetHashCodeTests()
Inconclusive()
IsFalse()
IsInstanceOfType()
IsNotInstanceOfType()
IsNotNull()
IsNull()
IsTrue()
|
Contains()
DoesNotMatch()
EndsWith()
Matches()
StartsWith()
|
AllItemsAreInstancesOfType()
AllItemsAreNotNull()
AllItemsAreUnique()
AreEqual()
AreEquivalent()
AreNotEqual()
AreNotEquivalent()
Contains()
DoesNotContain()
IsNotSubsetOf()
IsSubsetOf()
|
這些自動化單元測試用什么運行?
正如前面提到的,xUnit 框架將“測試運行器”的概念定義為應用程序負責:(a) 執行單元測試;(b) 報告測試結果。對于本文,包含 Visual Studio 2005 Team System (VSTS) 的 Unit Testing 引擎作為我們的“測試運行器”。圖 2 表示 BankAccountTests.cs 類的執行結果。
圖
2.
測試結果窗格:單元測試執行結果
Microsoft Visual Studio 2005 使用源項目的代碼模型動態填充該視圖。它基于該源代碼中的自定義屬性動態發現有關該測試套件的信息。表 4 表示最常見的單元測試屬性(以及執行的次序)。
TestClass()
|
該屬性表示一個測試裝置。
|
TestMethod()
|
該屬性表示一個測試用例。
|
AssemblyInitialize()
|
在執行為執行選擇的第一個 TestClass() 中的第一個 TestMethod() 之前,執行帶有該屬性的方法。
|
ClassInitialize()
|
帶有該屬性的方法在執行第一個測試之前調用。
|
TestInitialize()
|
帶有該屬性的方法在執行每個 TestMethod() 之前調用。
|
TestCleanup()
|
帶有該屬性的方法在執行每個 TestMethod() 之后調用。
|
ClassCleanup()
|
帶有該屬性的方法在執行 ALL 測試之后調用。
|
AssemblyCleanup()
|
在執行為執行選擇的第一個 TestClass() 中的第一個 TestMethod() 之后,執行帶有該屬性的方法。
|
Description()
|
提供關于給定 TestMethod() 的描述。
|
Ignore()
|
由于某種原因忽略 TestMethod() 或 TestClass()。
|
ExpectedException()
|
當測試特定異常時,如果使用該屬性指定的異常不是從實現代碼引發,則測試不會失敗。
|
我編寫什么類型的測試?
一個方法及其相關測試之間很難有一對一關系。編寫自動化單元測試需要開發人員“進行全面思考”,并了解關于對象的所有內容 — 它將如何消耗、使用、處理,以及在任何情況下如何起到積極、消極、非決定性作用。
例如,請考慮一個用于針對數據庫中 Customer 項執行 CRUD(創建、檢索、更新、刪除)功能的典型對象方法。對于該對象的 Load() 方法,要針對以下方案編寫測試:
? |
構造函數測試 — 確保對象正確加載,帶有正確的信息。
|
? |
PositiveLoadScalarTest — 測試數據庫中一個 Customer 的成功加載。
|
? |
NegativeLoadScalarTest — 測試一個 Customer 的失敗加載,即該 Customer 不在數據庫中。
|
? |
PositiveLoadTest — 基于已知數據測試 Customer 的成功加載。
|
? |
NegativeLoadTest — 測試數據庫中不存在的 Customer 的失敗加載。
|
? |
NegativeValidationTest — 確保驗證邏輯正確工作。
|
這些只是自動化單元測試套件許多用法中的一部分。我曾經聽說一個小團隊使用單元測試查看針對其組件的已知安全攻擊。從宏觀的角度來看,單元測試應該明確保證組件的正常使用。具有豐富的測試集將使團隊確信您已經準確實現了既定的目標:編寫有效的軟件。無論自信源自哪里 — 這就是您需要編寫的測試。
您測試什么?
從本質上看,這些自動化單元測試非常低級。它們旨在測試下至構造函數、方法調用的對象,甚至是對象上的屬性。
關于“公共對私有”的主題在單元測試派系中引發了許多爭論。許多人認為單元測試只應該測試對象的公共接口。其他人認為應該測試每個調用 — 包括內部私有方法。VSTS 支持兩個單元測試級別。VSTS 通過使用私有訪問器或包裝類支持私有測試,后者提供基于“私有”方法和屬性生成單元測試的功能。
為什么生成代碼?
閱讀上面的列表后,您可能會想起前面項目的單個對象,并思考:“如果我用“這些”對象進行該操作,就需要編寫大量代碼!”請考慮開發人員仍編寫“單元測試”代碼的事實 — 只在不同的窗體(例如,前面提到的 WinForms 示例)上進行。此外,具有可自行記錄、可重用的實現示例帶來的好處遠大于生成更多代碼所帶來的麻煩。最后,在單元測試中設計更多的環節已證明可以減少質量保證環節中的故障。
正如前面所提到的,代碼生成是“軟件創建軟件”的過程?;诳芍貜偷倪^程創建代碼是理想的。例如,一些使用代碼生成的較好示例包括:腳本數據、創建表示實體及其在儲存庫(數據庫 CRUD)中存在的對象,或者創建適用于數據維護的 UI 控件。使用代碼生成的好處包括:
? |
節省時間 — 為什么花幾小時/天/周創建一些在幾秒/分鐘內就可以創建的內容?
|
? |
強制標準
/
約定
— 對于強制您的標準和命名約定而言,沒有什么比消除開發中的人員因素并依賴基于“您的”規則的可重復過程更好的了。
|
? |
測試私有方法的功能 — 正如本文前面提到的,Unit Testing Framework 提供使用“私有訪問器”類測試私有方法的功能。該代碼生成引擎創建與這些訪問器類相關的所有“基礎代碼”。
|
? |
獲取現有組件的信息 — 搜索另一個開發人員的組件嗎?基于這些組件生成代碼可能提供關于該實現以及該對象接口的簡明示例。此外,進行設計并在編碼之前“清除”其對象的公共接口(例如,通過使用 VS 2005 類設計器)的開發人員將極大地受益于代碼生成引擎。
|
正如您所預期的,自動化單元測試屬于“優秀代碼生成候選者”。在現有組件中指出一些內容并針對這些自動單元測試生成初始代碼難道不是很理想嗎?而且不只是保留單元測試框架,還會圍繞對象的公共接口生成實現示例嗎?將來的 Visual Studio 2005 Team System 用戶將擁有該功能以及更多功能!
讓我們生成一些代碼吧!
本例中,我們將生成本文前面提到的 BankAccount 類的代碼。本文的這一部分旨在為您介紹代碼生成過程,并重點介紹所提供的功能以及從 VSTS 使用 Unit Testing 引擎的好處。
第 1 步:創建您的實現代碼
首先,我們創建一個將用作應用程序的業務層的類庫項目。
要在 VS 2005 中創建該庫:
1.
|
啟動 Visual Studio 2005 Beta 2。
|
2.
|
單擊 File | New | Project。
|
3.
|
選擇您選定的語言 Windows,并選擇 Class Library 項目模板。
|
4.
|
將 Name 和 Solution Name 設置為 BankAccountDemo.Business,選擇一個位置,并單擊 OK 來創建該類庫。
|
VS 2005 創建該類后,下一個任務就是創建針對您的項目設計的 BankAccount 類。為此,需要執行以下操作:
1.
|
在解決方案資源管理器中單擊右鍵,并單擊 Delete,從項目中移除該文件并將其從硬盤中刪除。
|
2.
|
右鍵單擊 BankAccountDemo.Business 項目,然后單擊 Add,之后單擊 Class。
|
3.
|
選擇文件名 BankAccount.cs,并單擊 Add 創建類文件。
|
4.
|
針對 BankAccount.cs 文件對代碼進行以下更改。
|
using System;
using System.Collections.Generic;
using System.Text;
namespace BankAccountDemo.Business
{
public class BankAccount
{
// Properties
private float _currentBalance;
public float CurrentBalance
{
get { return _currentBalance; }
}
// Constructors
public BankAccount(float initialBalance)
{
this._currentBalance = initialBalance;
}
// Methods
public void DepositMoney(float depositAmount)
{
this._currentBalance += depositAmount;
}
public void MakePayment(float paymentAmount)
{
this._currentBalance -= paymentAmount;
}
}
}
第 2 步:生成您的初始單元測試代碼
由于 Unit Testing 引擎內置于 Visual Studio 2005 Team System,因此生成代碼比以前更容易。除了生成單元測試結構之外,它將生成特定于實例的信息,例如,對象創建、類型化參數和方法執行。
VS 2005 提供在任何類結構級別生成單元測試代碼的功能,這些級別包括命名空間、類、方法、屬性、構造函數,等等??赏ㄟ^右鍵單擊這些代碼元素并單擊 Generate test(s)(圖 3)進行此操作。
圖
3. Generate test(s)
方法
因此,要開始代碼生成過程,請執行以下步驟:
? |
右鍵單擊該類名 BankAccount 并單擊 Create Tests。
|
現在,應該為您提供 Generate Unit Tests 對話框(如圖 4 所示)。該對話框及其組件提供對該過程中生成的代碼進行自定義的功能。讓我們看一下所有這些元素。
圖
4.
生成
Unit Tests
對話框
Current selection: 樹視圖允許導航自定義類及其元素。VS 2005 使用反射填充該樹視圖,并在右鍵單擊以及單擊 Create Tests 的位置自動選擇組件。圖 3 中,由于我在類級別進行了此操作,因此該對話框自動選擇用于代碼生成的所有類元素。如果選擇在單個級別(即,構造函數、屬性或方法)進行生成,則只選擇那些元素。
Filter 選項(位于右上角)提供修改樹視圖(圖 5)中所示結果的功能,包括顯示非公共項、基類型以及“只屬于我的代碼”。如果使用的是大型解決方案,或者感覺顯示私有的內部結構會弄亂選擇窗口,那么這對您很有益處。
圖
5.
篩選選擇結果
下一個是 Output project 對話框(位于 Current selection: 樹視圖下)。該列表框允許您針對生成的測試裝置選擇目的項目(圖 6)。如果您的解決方案包含以前創建的測試項目,則將包含該測試項目以供選擇。由于這是我們首次訪問該對話框,因此可以選擇 Create a new … Test Project 選項。
圖
6.
輸出項目選擇
要繼續我們的過程,請執行以下操作:
? |
基于您選擇的語言選擇 Create a new {0} Test Project。
|
最后,該對話框提供通過 Settings 按鈕(位于左下角)自定義代碼生成過程的功能。單擊該按鈕將加載 Test Generation Settings 對話框,如圖 7 所示。
圖
7. Test Generation Settings
對話框
該對話框允許您進行以下更改:
? |
更改命名約定,它們用于生成針對文件、類(測試裝置)和方法(測試)的名稱。
|
? |
打開/關閉使所有測試結果在默認情況下為 Inconclusive 的功能。選擇該選項將在每個生成的 Test() 方法中包含以下占位符語句。
Assert.Inconclusive("TODO: Implement code to verify target");
|
? |
打開/關閉啟用生成警告的功能 — 即,如果在代碼生成過程中出現任何警告,都要進行報告。
|
? |
在全局范圍內限制所有類型。該設置通知代碼生成引擎將一個全局限定符(在 Microsoft Visual C# 2005 中是 global::)添加到變量聲明中。當在多個命名空間中具有名稱相似的對象時,請使用該設置。否則,代碼生成引擎將創建邏輯來創建該對象,但是編譯器不能確定創建哪個類,因此會產生錯誤。
|
? |
啟用/禁用針對已具有測試的項生成測試的功能。下面我們將討論關于后續代碼生成嘗試的主題。
|
? |
啟用/禁用文檔注釋。這允許您在使用每個 Test() 方法時禁用 XML 文檔的創建
|
要完成我們的配置并生成單元測試代碼(以及更多),請執行以下操作:
1.
|
單擊 OK 按鈕開始代碼生成過程。
|
2.
|
輸入名稱 BankAccountDemo.Business.Test 作為新項目名,并單擊 Create 按鈕完成該過程。
|
VS 2005 將顯示一個進度欄,提供代碼生成過程中的狀態。該過程將在幾秒鐘內完成,您可以看到一個名為 BankAccountTest.cs 的類。
生成了什么?
在我們對該測試裝置進行特別查看之前,讓我們看一下在代碼生成過程中創建了什么。
首先,它創建了 Test Class Library 項目 BankAccountDemo.Business.Test。請注意該項目如何包含對實現類 BankAccountDemo.Business(您從其中生成代碼)和 Microsoft.VisualStudio.QualityTools.UnitTestFramework 類庫的引用。在查看該類的內容時,您將注意到以下文件:
? |
AuthoringTests.txt — 這是一些信息性的內容,定義如何使用單元測試(打開、查看、運行、查看結果、更改測試的運行方式),以及 VSTS 中包含的不同測試類型的定義。
|
? |
ManualTest1.mht — 這是 VSTS 中使用的手動測試套件,用于執行測試并報告結果。手動測試是 VSTS 支持的一個附加測試類型。有關更多信息,請參閱 MSDN 資源庫的“手動測試”主題。
|
? |
UnitTest1.cs — 這是一個引用類,它只提供一個基單元測試(包括 TestClass、TestInitialize、TestCleanup 和 TestMethod 的定義)。
|
? |
BankAccountTest.cs — 這是特定于程序集生成的單元測試代碼。讓我們仔細看看該代碼,它是代碼生成過程中最重要的部分。
|
由 Unit Testing 引擎生成的類包括以下組件:
? |
Using/imports 語句,用于引用的程序集。
|
? |
TestClass() 定義,用于包含該測試的類 (BankAccountTestFixture)。
|
? |
一個私有訪問器和用于 TestContext 的公共屬性。它由單元測試運行器(即 VSTS Unit Test Framework)使用,以便提供關于當前測試運行的信息以及用于該運行的功能。
|
? |
TestInitialize() 和 TestCleanup() 方法。這些方法常用于獲取和釋放測試所需的任何對象。
|
? |
TestMethod(),用于每個選定的方法。
|
讓我們仔細看一下 DepositMoneyTest(),它負責確保當前的平衡能反映原始數量與累計數量的總和。
///
///A test case for DepositMoney (float)
///
[TestMethod()]
public void DepositMoneyTest()
{
float initialBalance = 0; // TODO: Initialize to an appropriate value
BankAccount target = new BankAccount(initialBalance);
float depositAmt = 0; // TODO: Initialize to an appropriate value
target.DepositMoney(depositAmt);
Assert.Inconclusive("A method that does not return a value" +
"cannot be verified.");
}
請注意該生成引擎除創建一個 stub TestMethod() 對象外,是如何進行其他操作的。它創建了適用于接口的示例單元測試,包括:
? |
BankAccount 對象的分配和結構(測試的對象主題)
|
? |
本地變量的創建和默認分配,這些變量表示作為該測試主題的方法/構造函數所需的參數。
? |
TODO 注釋,提醒開發人員適當地分配參數變量。
|
|
? |
如果測試基于一個源對象方法調用,則生成的代碼將包含對該方法(帶有用于這些參數的局部變量)的調用。
|
? |
初始 Assert() 方法調用,基于該方法的返回值。
|
? |
Assert.Inconclusive() 方法調用,作為完成測試代碼的提示程序。非確定性測試將在 Test Results 對話框中顯示為失敗。
|
生成后:我現在需要做什么?
考慮要完成相同的操作可以不必做哪些事情,則通常可以認識到代碼生成的好處。在我們的示例中,我們不必:
? |
創建單元測試項目。
|
? |
設置項目引用。
|
? |
添加適當的測試類(一個或多個)。
|
? |
生成主干 Unit Test Framework 類和屬性。
|
? |
創建單個測試方法。
|
? |
創建特定于接口的邏輯。
|
由于代碼生成過程創建了特定于對象接口的示例單元測試,因此我們接近于初始測試的完成階段了。通常情況下,只需“填充空白”并完成斷言(一個或多個),方法是將“已知的數據值”分配給屬性變量并創建適當的 Assert() 方法。顯然,這不是針對所有測試的示例,特別是對具有多個斷言的復雜測試而言。
只需幾秒鐘的時間(使用相對較少的擊鍵),您就能夠將生成的單元測試代碼轉換為這些實際的測試。
例如,請考慮我們以如下方式開始。
[TestMethod()]
public void DepositMoneyTest()
{
float initialBalance = 0; // TODO: Initialize to an appropriate value
BankAccount target = new BankAccount(initialBalance);
float depositAmt = 0; // TODO: Initialize to an appropriate value
target.DepositMoney(depositAmt);
Assert.Inconclusive("A method that does not return a value " +
"cannot be verified.");
}
我們能夠完成相對容易且具有有限擊鍵的測試(更改部分用黑體表示)。
[TestMethod()]
public void DepositMoneyTest() {
float currentBalance = 500;
BankAccount target = new BankAccount(currentBalance);
float depositAmt = 10;
target.DepositMoney(depositAmt);
Assert.AreEqual(currentBalance + depositAmt, target.CurrentBalance,
"Deposit Test: Deposit not applied correctly");
}
重新生成單元測試代碼
好消息是,代碼生成過程不會讓您重寫以前生成(和修改)的單元測試。使用 Visual Studio 2005 Team System 的 Beta 2 版本,代碼生成選項提供一個啟用/禁用創建已存在測試的復選框。如果選擇它,而且該過程找到了一個具有相同名稱的現有測試,則該過程將忽略該測試方法,并創建后續測試,從而將一個數字附加到該方法名的末尾。這通常在對象中使用重載的方法或構造函數時發生,或者當單擊 Generate 按鈕而不取消選定現有測試時發生。
自動化單元測試建議
雖然本節可以獨立成文,但這里只是一些您在創建單元測試時可以采納的基本建議。
? |
設計彼此獨立的單元測試,其中它們可以獨立運行(由于可以通過測試 UI 隨意選擇或取消選定它們)。
|
? |
不要只進行正面測試。請確保代碼能夠響應任何方案,包括發生意外時(資源不可用,數據庫只讀等)。
|
? |
把自己當作一個 QA 人員,想象成一個測試人員,而不僅僅是一個開發人員。您花在設計單元測試上的時間將有助于減少日后解決故障所用的時間。請注意對象的幾個小細節:數據如何在對象之間傳輸?誰使用它們?銷毀對象容易嗎?如果我“進行此操作”,將會發生什么?
|
? |
跳出您自己的思維模式。盡可能多地對測試進行頭腦風暴。當您完成時,回頭查看您可能漏掉的內容。來自團隊成員的請求反饋 — 例如,他們創建了什么其他類型的測試?其他人可能提供一個對熟悉自己代碼的開發人員而言非常困難的觀點。
|
? |
代碼覆蓋。使用 VSTS 代碼覆蓋規范提供有關每個測試運行中實際執行多少代碼的信息(代碼的行數,占所有代碼的百分比)。如果編碼完成,并且通過了所有測試,但代碼覆蓋顯示只執行了該邏輯的一小部分,那么您的測試真的成功了嗎?高代碼覆蓋不一定意味著您具有一個完整的“測試”集,而未覆蓋的代碼通常非常適用于一個新的測試用例。
|
? |
當生成單元測試時,要幫助其他人了解您的代碼:
? |
使用一個項目結構,該結構映射所測試程序集的結構。
每個程序集有一個相關的測試程序集。
每個類有一個相關的測試類。
在各自的測試方法中包含每個方法名(即,Load() 將有 PositiveLoadTest()、NegativeLoadTest()、PositiveScalarLoadTest() 等的測試方法)。
|
? |
使用一致的命名協定,包括對象的屬性和方法名。
|
|
? |
此外,當其他所有測試都失敗時,請進行調試。自動化單元測試應該有助于減少您用在調試器上的時間。但是,如果測試結果和代碼覆蓋無法提供測試失敗的原因,那么您大可不必擔心調試單元測試。從 Beta 2 版的 Visual Studio 2005 Team System 開始,開發人員可以使用 Test Manager 中的 Debug checked tests 選項調試他們的單元測試程序集。
|
小結
自動化單元測試為開發環節提供了一個結構化、自行紀錄、高度便攜且可重復的過程。如果在搜索現有程序集,或者如果開發環境需要在開始開發之前進行完整的設計,則請考慮使用內置到 Microsoft Visual Studio 2005 Team System 中的代碼生成引擎。Visual Studio 2005 Team System 的單元測試代碼生成功能可以為您節省寶貴的時間,而且有助于強制團隊的開發標準和約定。通過生成用于自動化單元測試的基本內容,包括生成帶有對象創建的測試方法、參數變量和基斷言類,您應該能夠順利地在您的開發方法論中采用自動化單元測試。
作者簡介
作為針對 telligent 系統的專業服務主管,Scott Dockendorf 擅長于用 .NET 提供高性能、可伸縮的應用程序。Scott 熱衷于解決方案體系結構、安全開發,他通過標準和已通過驗證的方法論幫助企業采用推薦的實踐。Scott 是 .NET 社區的一個積極成員,他自愿作為 North Dallas .NET User Group 的程序主管。他還參加了面向本地 .NET 用戶組的會議,而且是 INETA's International Academic Committee for Texas 的活躍分子。您可以通過他的電子郵件 (scottd@telligent.com) 或網絡日記 (http://weblogs.asp.net/scottdockendorf) 與他聯系。
轉到原英文頁面