逐步解說:以使用時產生功能支援測試優先
本主題示範如何使用可支援測試優先開發的使用時產生功能。
「測試優先開發」(Test-First Development) 是一種軟體設計方式,其中,您會先根據產品規格撰寫單元測試,然後撰寫讓測試成功所需的原始程式碼。 Visual Studio 支援測試優先開發,在您尚未定義新型別和成員就要在測試案例中參照新型別和成員時,可以先在原始程式碼中產生這些型別和成員。
Visual Studio 會在對您的工作流程造成最少干擾的情況下產生新的型別和成員。 您可以建立型別、方法、屬性、欄位或建構函式的 Stub,而不需要離開程式碼中目前的位置。 當您開啟對話方塊以指定型別產生選項時,焦點會在關閉對話方塊之後立即回到目前開啟的檔案。
[使用時產生] 功能可以與整合 Visual Studio 的測試架構搭配使用。 本主題會示範 Microsoft Unit Testing Framework。
注意事項 |
---|
您的電腦可能會在下列說明中,以不同名稱或位置顯示某些 Visual Studio 使用者介面項目。您所擁有的 Visual Studio 版本以及使用的設定會決定這些項目。如需詳細資訊,請參閱 Visual Studio 設定。 |
若要建立 Windows 類別庫專案和測試專案
在 Visual C# 或 Visual Basic 中,建立新的 Windows 類別庫專案。 並將它命名為 GFUDemo_VB 或 GFUDemo_CS,視您所使用的語言而定。
在 [方案總管] 中,以滑鼠右鍵按一下頂端的方案圖示,並指向 [加入],然後按一下 [新增專案]。 在 [新增專案] 對話方塊左側的 [專案類型] 窗格中,按一下 [測試]。
在範本 ] 窗格中,按一下 單元測試專案 ,並接受預設名稱的 UnitTestProject1。 下圖顯示對話方塊出現在 Visual C# 中的樣子。 在 Visual Basic 中,這個對話方塊十分類似。
新增專案對話方塊
按一下 [確定] 關閉 [新增專案] 對話方塊。 您現在可以準備開始撰寫測試。
若要透過單元測試產生新類別
測試專案包含 UnitTest1 檔案。 按兩下 [方案總管] 中的這個檔案,在 [程式碼編輯器] 中開啟這個檔案。 已產生測試類別和測試方法。
找到 UnitTest1 類別的宣告,並將它重新命名為 AutomobileTest。 在 C# 中,如果具有 UnitTest1() 建構函式,則請將它重新命名為 AutomobileTest()。
注意事項 IntelliSense 現在為 IntelliSense 陳述式完成提供兩個選項:「完成模式」(Completion Mode) 和「建議模式」(Suggestion Mode)。在尚未定義就要使用類別和成員的情況下,請使用建議模式。當 IntelliSense 視窗開啟時,按下 CTRL+ALT+空格鍵,即可在完成模式和建議模式間進行切換。如需詳細資訊,請參閱 使用 IntelliSense。在您於下一個步驟輸入 Automobile 時,建議模式十分有幫助。
找到 TestMethod1() 方法,並將它重新命名為 DefaultAutomobileIsInitializedCorrectly()。 在這個方法內,建立名為 Automobile 類別的新執行個體,如下圖所示。 會出現波形底線,表示編譯時期錯誤,而且會在型別名稱底下出現智慧標籤。 智慧標籤的確切位置會隨著您使用 Visual Basic 還是 Visual C# 而不同。
Visual Basic
Visual C#
將滑鼠指標置於智慧標籤上方,就會看到一則錯誤訊息,指出尚未定義 Automobile 類型。 按一下智慧標籤,或按 CTRL+. (CTRL+句點) 開啟 [使用時產生] 捷徑功能表 (如下圖所示)。
Visual Basic
Visual C#
您現在有兩種選擇。 您可以按一下 [產生 'Class Automobile'] 以在測試專案中建立新檔案,並在其中填入空的 Automobile 類別。 若要在目前專案的新檔案中建立含有預設存取修飾詞的新類別,這是十分快速的方式。 您也可以按一下 [產生新的型別] 開啟 [產生新的型別] 對話方塊。 提供的選項包括在現有檔案中放置類別,以及將檔案加入至其他方案。
按一下 [產生新的型別] 開啟 [產生新的型別] 對話方塊 (如下圖所示)。 按一下 [專案] 清單中的 [GFUDemo_VB] 或 [GFUDemo_CS],指示 Visual Studio 將檔案加入至原始程式碼專案,而不是測試專案。
產生新的型別對話方塊
按一下 [確定] 關閉對話方塊,並建立新的檔案。
在 [方案總管] 中,查看 GFUDemo_VB 或 GFUDemo_CS 專案節點,確認新的 Automobile.vb 或 Automobile.cs 檔案已存在。 在 [程式碼編輯器] 中,焦點還是在 AutomobileTest.DefaultAutomobileIsInitializedCorrectly 中。 您可以在干擾最少的情況下繼續撰寫測試。
若要產生屬性 Stub
假設產品規格指出 Automobile 類別有兩個公用屬性:Model 和 TopSpeed。 預設建構函式必須使用預設值 "Not specified" 和 -1 初始化這些屬性。 下列單元測試會確認預設建構函式將屬性設為其正確預設值。
請將下列程式碼加入至 DefaultAutomobileIsInitializedCorrectly。
Assert.IsTrue((myAuto.Model = "Not specified") And (myAuto.TopSpeed = -1))
Assert.IsTrue((myAuto.Model == "Not specified") && (myAuto.TopSpeed == -1));
程式碼在 Automobile 上參照兩個未定義的屬性,因此會出現智慧標籤。 請按一下 Model 的智慧標籤,然後按一下 [產生屬性 Stub]。 也請產生 TopSpeed 屬性的屬性 Stub。
在 Automobile 類別,會透過內容正確地推論出新屬性的型別。
下圖顯示智慧標籤捷徑功能表。
Visual Basic
Visual C#
若要尋找原始程式碼
使用 [巡覽至] 功能巡覽至 Automobile.cs 或 Automobile.vb 原始程式碼檔,確認已產生新屬性。
[巡覽至] 功能可讓您快速輸入文字字串 (例如型別名稱或名稱的一部分),然後按一下結果清單中的項目跳至想要的位置。
在 [程式碼編輯器] 內按一下,並按 CTRL+, (CTRL+逗點),開啟 [巡覽至] 對話方塊。 在文字方塊中,輸入 automobile。 按一下清單中的 [Automobile] 類別,然後按一下 [確定]。
下圖顯示 [巡覽至] 視窗。
巡覽至視窗
若要產生新建構函式的 Stub
使用這種測試方法,您會產生建構函式 Stub,用以初始化 Model 和 TopSpeed 屬性,使其具有您指定的值。 稍後,您將加入其他程式碼來完成測試。 請將下列其他測試方法加入至 AutomobileTest 類別。
<TestMethod()> Public Sub AutomobileWithModelNameCanStart() Dim model As String = "Contoso" Dim topSpeed As Integer = 199 Dim myAuto As New Automobile(model, topSpeed) End Sub
[TestMethod] public void AutomobileWithModelNameCanStart() { string model = "Contoso"; int topSpeed = 199; Automobile myAuto = new Automobile(model, topSpeed); }
請按一下新類別建構函式底下的智慧標籤,然後按一下 [產生建構函式 Stub]。 在 Automobile 類別檔中,請注意,新的建構函式已檢查在建構函式呼叫中使用的本機變數名稱,發現屬性的名稱與 Automobile 類別中的項目同名,並在建構函式主體內提供程式碼以將引數值儲存至 Model 和 TopSpeed 屬性中 (在 Visual Basic 中,新建構函式中的 _model 和 _topSpeed 欄位是 Model 和 TopSpeed 屬性的隱含定義之支援欄位)。
在您產生新的建構函式之後,會在 DefaultAutomobileIsInitializedCorrectly 的預設建構函式呼叫底下出現波形底線。 錯誤訊息指出 Automobile 類別沒有採用零引數的建構函式。 若要產生沒有參數的明確預設建構函式,請按一下智慧標籤,然後按一下 [產生建構函式 Stub]。
若要產生方法的 Stub
假設規格指出新的 Automobile 在其 Model 和 TopSpeed 屬性設為預設值以外的值時,可以進入 [執行中] 狀態。 將下列各行加入至 AutomobileWithModelNameCanStart 方法。
myAuto.Start() Assert.IsTrue(myAuto.IsRunning = True)
myAuto.Start(); Assert.IsTrue(myAuto.IsRunning == true);
按一下 myAuto.Start 方法呼叫的智慧標籤,然後按一下 [產生方法 Stub]。
按一下 IsRunning 屬性的智慧標籤,然後按一下 [產生屬性 Stub]。 Automobile 類別現在包含下列程式碼。
Public Class Automobile Sub New(ByVal model As String, ByVal topSpeed As Integer) _model = model _topSpeed = topSpeed End Sub Sub New() ' TODO: Complete member initialization End Sub Property Model() As String Property TopSpeed As Integer Property IsRunning As Boolean Sub Start() Throw New NotImplementedException End Sub End Class
public class Automobile { public string Model { get; set; } public int TopSpeed { get; set; } public Automobile(string model, int topSpeed) { this.Model = model; this.TopSpeed = topSpeed; } public Automobile() { // TODO: Complete member initialization } public void Start() { throw new NotImplementedException(); } public bool IsRunning { get; set; } }
若要執行測試
在單元測試 功能表上指向 執行單元測試,然後按一下 的所有測試。 這個命令會在所有針對目前方案撰寫的測試架構中執行所有測試。
在此情況下,會進行兩項測試,而且都會如預期失敗。 DefaultAutomobileIsInitializedCorrectly 測試因 Assert.IsTrue 條件傳回 False 而失敗。 AutomobileWithModelNameCanStart 測試因 Automobile 類別中的 Start 方法擲回例外狀況而失敗。
下圖顯示 [測試結果] 視窗。
測試結果視窗
在 [測試結果] 視窗中,按兩下每個測試結果列以移至每個測試失敗的位置。
若要實作原始程式碼
將下列程式碼加入至預設建構函式,讓 Model、TopSpeed 和 IsRunning 屬性全部都初始化為其正確預設值 "Not specified"、-1 和 True (true)。
Sub New() Model = "Not specified" TopSpeed = -1 IsRunning = True End Sub
public Automobile() { this.Model = "Not specified"; this.TopSpeed = -1; this.IsRunning = true; }
呼叫 Start 方法時,只有在 Model 或 TopSpeed 屬性設為預設值以外的值時,才應該將 IsRunning 旗標設為 true。 請從方法主體中移除 NotImplementedException,並加入下列程式碼。
Sub Start() If Model <> "Not specified" Or TopSpeed <> -1 Then IsRunning = True Else IsRunning = False End If End Sub
public void Start() { if (this.Model != "Not specified" || this.TopSpeed != -1) this.IsRunning = true; else this.IsRunning = false; }
若要重新執行測試
指向 [測試] 功能表上的 [執行],然後按一下 [方案中的所有測試]。 這次會通過測試。 下圖顯示 [測試結果] 視窗。
測試結果視窗