開始使用 Live Unit Testing
當您在 Visual Studio 解決方案中啟用 Live Unit Testing 時,它會以可視化方式描述您的測試涵蓋範圍和測試狀態。 即時單元測試也會在您修改程式碼時動態執行測試,並在變更導致測試失敗時立即通知您。
Live Unit Testing 可用來測試以 .NET Framework、.NET Core 或 .NET 5+ 為目標的解決方案。 在本教學課程中,您將瞭解如何建立以 .NET 為目標的簡單類別庫,並建立以 .NET 為目標的 MSTest 專案,以測試它。
您可以從 GitHub 上的 MicrosoftDocs/visualstudio-docs 存放庫下載完整的 C# 解決方案。
先決條件
本教學課程需要您已安裝 Visual Studio Enterprise 版本,並選擇 .NET 桌面開發 工作負載。
建立方案和類別庫專案
首先,建立名為 UtilityLibraries 的 Visual Studio 解決方案,其中包含單一 .NET 類別庫專案 StringLibrary。
解決方案只是一或多個專案的容器。 若要建立空白解決方案,請開啟 Visual Studio 並執行下列動作:
從最上層的 Visual Studio 功能表中,選取 [檔案>新增>專案]。
在範本搜尋框中輸入 解決方案,然後選取 空白解決方案 範本。 將專案命名 UtilityLibraries。
完成建立解決方案。
既然您已建立解決方案,您將建立名為 StringLibrary 的類別庫,其中包含一些用於處理字串的擴充方法。
在 [方案總管]中,以滑鼠右鍵按兩下 UtilityLibraries 方案,然後選取 [新增>新增專案]。
在範本搜尋方塊中輸入 類別庫,然後選取以 .NET 或 .NET Standard 為目標的 類別庫 範本。 點選 [下一步]。
將專案命名 StringLibrary。
按一下 建立 以建立專案。
用以下程式碼取代程式碼編輯器中的所有現有程式碼:
using System; namespace UtilityLibraries { public static class StringLibrary { public static bool StartsWithUpper(this string s) { if (String.IsNullOrWhiteSpace(s)) return false; return Char.IsUpper(s[0]); } public static bool StartsWithLower(this string s) { if (String.IsNullOrWhiteSpace(s)) return false; return Char.IsLower(s[0]); } public static bool HasEmbeddedSpaces(this string s) { foreach (var ch in s.Trim()) { if (ch == ' ') return true; } return false; } } }
StringLibrary 有三個靜態方法:
如果字串以大寫字元開頭,
StartsWithUpper
會傳回true
;否則,它會傳回false
。如果字串以小寫字元開頭,
StartsWithLower
會傳回true
;否則,它會傳回false
。如果字串包含內嵌空格符,
HasEmbeddedSpaces
會傳回true
;否則,它會傳回false
。
從最上層 Visual Studio 功能表選取 [建置>建置方案]。 組建應該會成功。
建立測試專案
下一個步驟是建立單元測試項目來測試 StringLibrary 連結庫。 執行下列步驟來建立單元測試:
在 [方案總管]中,以滑鼠右鍵按一下 UtilityLibraries 方案,然後選取 新增>新增專案。
在範本搜尋方塊中輸入 單元測試,選取 C# 作為語言,然後選取適用於 .NET 範本 MSTest 單元測試專案。 點選 [下一步] 。
注意
在Visual Studio 2019 16.9版中,MSTest專案範本名稱 單元測試專案。
將專案命名為 StringLibraryTests,然後按 [下一步]。
選擇建議的目標 Framework 或 .NET 8,然後選擇「建立」。
注意
本快速入門教學課程使用 Live Unit Testing 搭配 MSTest 測試架構。 您也可以使用 xUnit 和 NUnit 測試架構。
單元測試項目無法自動存取正在測試的類別庫。 您可以透過新增類別庫項目的參考來存取測試庫。 若要這樣做,請以滑鼠右鍵按下
StringLibraryTests
項目,然後選取 新增>項目參考。 在 [參考管理員] 對話框中,確定已選取 [方案] 索引卷標,然後選取 StringLibrary 專案,如下圖所示。以下列程式代碼取代範本所提供的未定案單元測試程式代碼:
using System; using Microsoft.VisualStudio.TestTools.UnitTesting; using UtilityLibraries; namespace StringLibraryTest { [TestClass] public class UnitTest1 { [TestMethod] public void TestStartsWithUpper() { // Tests that we expect to return true. string[] words = { "Alphabet", "Zebra", "ABC", "Αθήνα", "Москва" }; foreach (var word in words) { bool result = word.StartsWithUpper(); Assert.IsTrue(result, $"Expected for '{word}': true; Actual: {result}"); } } [TestMethod] public void TestDoesNotStartWithUpper() { // Tests that we expect to return false. string[] words = { "alphabet", "zebra", "abc", "αυτοκινητοβιομηχανία", "государство", "1234", ".", ";", " " }; foreach (var word in words) { bool result = word.StartsWithUpper(); Assert.IsFalse(result, $"Expected for '{word}': false; Actual: {result}"); } } [TestMethod] public void DirectCallWithNullOrEmpty() { // Tests that we expect to return false. string[] words = { String.Empty, null }; foreach (var word in words) { bool result = StringLibrary.StartsWithUpper(word); Assert.IsFalse(result, $"Expected for '{(word == null ? "<null>" : word)}': " + $"false; Actual: {result}"); } } } }
選取工具列上的 [儲存] 圖示,以儲存專案。
因為單元測試程式代碼包含一些非 ASCII 字元,因此您會看到下列對話框警告,如果您以預設 ASCII 格式儲存盤案,某些字元將會遺失。
選擇 [以其他編碼儲存] 按鈕。
在 [進階儲存選項] 對話框的 [編碼] 下拉式清單中,選擇 [Unicode ][UTF-8 不含簽章] - Codepage 65001,如下圖所示:
編譯單元測試專案,從 Visual Studio 的頂層功能表選取 [建置>重建方案]。
您已建立一個類別庫及一些為它所做的單元測試。 您現在已完成使用 Live Unit Testing 所需的預備專案。
啟用 Live Unit Testing
到目前為止,雖然您已撰寫 StringLibrary 類別庫的測試,但尚未執行它們。 即時單元測試會在您啟用之後自動執行。 若要這樣做,請執行下列動作:
或者,選取包含 StringLibrary 程式代碼的程式碼編輯器視窗。 這是 C# 專案的 Class1.cs,或 Visual Basic 專案的 Class1.vb。 (此步驟可讓您在啟用 Live Unit Testing 之後,以可視化方式檢查測試的結果和程式碼涵蓋範圍。
從 Visual Studio 功能表的最上層選取 測試>Live Unit Testing>開始。
確認 Live Unit Testing 的設定,方法是確保存放庫根目錄包含公用程式專案和測試專案的來源檔案路徑。 選取 下一步,然後 完成。
在 [Live Unit Testing] 視窗中,選取 包含所有測試 連結(或者,選取 [播放清單] 按鈕圖示,然後選取 [StringLibraryTest] 以選取其下的所有測試。然後取消選取 [播放清單] 按鈕以結束編輯模式。)
Visual Studio 會重建專案並啟動 Live Unit Test,以自動執行所有測試。
- Visual Studio 會重建專案並啟動 Live Unit Test,以自動執行所有測試。
當測試完成執行時,Live Unit Testing 會顯示整體結果和個別測試的結果。 此外,程式代碼編輯器視窗會以圖形方式顯示您的測試程式代碼涵蓋範圍和測試結果。 如下圖所示,這三個測試都已順利執行。 它也顯示我們的測試已涵蓋 StartsWithUpper
方法中的所有程式代碼路徑,而且這些測試都已成功執行(綠色複選標記 “✓” 表示)。 最後,它顯示 StringLibrary 中沒有任何其他方法具有程式代碼涵蓋範圍(以藍線 “” ➖ 表示)。
之後,Live Test Explorer 和程式碼編輯器視窗
您也可以在程式代碼編輯器視窗中選取特定的程式代碼涵蓋範圍圖示,以取得測試涵蓋範圍和測試結果的詳細資訊。 若要檢查此詳細數據,請執行下列動作:
點擊
StartsWithUpper
方法中顯示if (String.IsNullOrWhiteSpace(s))
的那行的綠色核取標記。 如下圖所示,Live Unit Testing 指出三個測試涵蓋該程式代碼行,而且所有測試都已順利執行。按一下在
StartsWithUpper
方法中讀取return Char.IsUpper(s[0])
行的綠色勾選標記。 如下圖所示,Live Unit Testing 指出只有兩個測試涵蓋該程式代碼行,而且所有測試都已順利執行。
Live Unit Testing 識別的主要問題是程式碼覆蓋率不足。 您將在下一節中處理這個問題。
展開測試涵蓋範圍
在本節中,您會將單元測試延伸至 StartsWithLower
方法。 當您這樣做時,Live Unit Testing 會動態地繼續測試您的程式代碼。
若要將程式代碼涵蓋範圍擴充至 StartsWithLower
方法,請執行下列動作:
將下列
TestStartsWithLower
和TestDoesNotStartWithLower
方法新增至專案的測試原始碼檔案:// Code to add to UnitTest1.cs [TestMethod] public void TestStartsWithLower() { // Tests that we expect to return true. string[] words = { "alphabet", "zebra", "abc", "αυτοκινητοβιομηχανία", "государство" }; foreach (var word in words) { bool result = word.StartsWithLower(); Assert.IsTrue(result, $"Expected for '{word}': true; Actual: {result}"); } } [TestMethod] public void TestDoesNotStartWithLower() { // Tests that we expect to return false. string[] words = { "Alphabet", "Zebra", "ABC", "Αθήνα", "Москва", "1234", ".", ";", " "}; foreach (var word in words) { bool result = word.StartsWithLower(); Assert.IsFalse(result, $"Expected for '{word}': false; Actual: {result}"); } }
藉由在呼叫
Microsoft.VisualStudio.TestTools.UnitTesting.Assert.IsFalse
方法之後立即新增下列程序代碼,以修改DirectCallWithNullOrEmpty
方法。// Code to add to UnitTest1.cs result = StringLibrary.StartsWithLower(word); Assert.IsFalse(result, $"Expected for '{(word == null ? "<null>" : word)}': " + $"false; Actual: {result}");
Live Unit Testing 會在您修改原始程式碼時自動執行新的和已修改的測試。 如下圖所示,所有測試,包括您已新增的兩個測試,以及您已修改的測試都成功。
在擴大測試覆蓋範圍後,
在擴展測試覆蓋範圍之後,
切換至包含 StringLibrary 類別原始程式碼的視窗。 Live Unit Testing 現在會顯示我們的程式代碼涵蓋範圍延伸至
StartsWithLower
方法。
在某些情況下,測試總管 中成功的測試可能會呈現灰色。這表示測試目前正在執行,或測試尚未再次執行,因為自上次執行以來,沒有任何程式碼變更會影響測試。
到目前為止,我們所有的測試都成功了。 在下一節中,我們將檢查如何處理測試失敗。
處理測試失敗
在本節中,您將探索如何使用 Live Unit Testing 來識別、疑難解答及解決測試失敗。 您將透過將測試涵蓋範圍擴展至 HasEmbeddedSpaces
方法來實現這一點。
將下列方法新增至您的測試檔案:
[TestMethod] public void TestHasEmbeddedSpaces() { // Tests that we expect to return true. string[] phrases = { "one car", "Name\u0009Description", "Line1\nLine2", "Line3\u000ALine4", "Line5\u000BLine6", "Line7\u000CLine8", "Line0009\u000DLine10", "word1\u00A0word2" }; foreach (var phrase in phrases) { bool result = phrase.HasEmbeddedSpaces(); Assert.IsTrue(result, $"Expected for '{phrase}': true; Actual: {result}"); } }
當測試執行時,Live Unit Testing 表示
TestHasEmbeddedSpaces
方法失敗,如下圖所示:選取顯示連結庫程式碼的視窗。 Live Unit Testing 已將程式代碼涵蓋範圍擴充至
HasEmbeddedSpaces
方法。 它也會將紅色的“🞩”新增至失敗測試所涵蓋的行,以報告測試失敗。將滑鼠停留在具有
HasEmbeddedSpaces
方法簽章的行上。 Live Unit Testing 顯示提示訊息,說明該方法已被一個測試涵蓋,如圖所示:的 Live Unit Testing 資訊
的 Live Unit Testing 資訊
選擇失敗的「TestHasEmbeddedSpaces」測試。 Live Unit Testing 提供一些選項,例如執行所有測試和偵錯所有測試,如下圖所示:
的 Live Unit Testing 選項
選取 [[偵錯所有],以偵錯失敗的測試。
Visual Studio 會在偵錯模式中執行測試。
測試會將陣列中的每個字串指派給名為
phrase
的變數,並將它傳遞給HasEmbeddedSpaces
方法。 程序執行會在第一次false
斷言表達式時暫停,並啟動調試器。 下圖顯示Microsoft.VisualStudio.TestTools.UnitTesting.Assert.IsTrue
方法呼叫中非預期值所產生的例外狀況對話方塊。此外,Visual Studio 提供的所有偵錯工具都可用來協助我們針對失敗的測試進行疑難解答,如下圖所示:
請注意,在 [Autos] 視窗中,
phrase
變數的值是 “Name\tDescription”,這是陣列的第二個元素。 測試方法預期在傳遞此字串時HasEmbeddedSpaces
傳回true
;相反地,它會傳回false
。 顯然,它無法將 “\t” 製表符辨識為內嵌空格。選取 [偵錯>繼續]、按 F5,或 按兩下工具列上的 [繼續] 按鈕,繼續執行測試程式。 因為發生未處理的例外狀況,因此測試會終止。 這會提供足夠的資訊,以便對 Bug 進行初步調查。
TestHasEmbeddedSpaces
(測試例程)做出不正確的假設,或HasEmbeddedSpaces
無法正確辨識所有內嵌空格。若要診斷並更正問題,請從
StringLibrary.HasEmbeddedSpaces
方法開始。 查看HasEmbeddedSpaces
方法中的比較。 它會將內嵌空間視為U+0020。 不過,Unicode 標準包含一些其他空格字元。 這表示連結庫程式代碼未正確測試空格符。將相等比較取代為對 System.Char.IsWhiteSpace 方法的呼叫:
if (Char.IsWhiteSpace(ch))
Live Unit Testing 會自動重新執行失敗的測試方法。
Live Unit Testing 會顯示更新的結果,也會出現在程式代碼編輯器視窗中。
相關內容
- Visual Studio 中的 Live Unit Testing
- Live Unit Testing 常見問題