注:本文示例環境數組
VS2017
XUnit 2.2.0 單元測試框架
xunit.runner.visualstudio 2.2.0 測試運行工具
Moq 4.7.10 模擬框架網絡
確保軟件應用程序按做者的指望執行操做,其中最好的一種方法是擁有自動化測試套件。 能夠對軟件應用程序進行各類不一樣的測試,包括集成測試、Web 測試、負載測試等。 測試各個軟件組件或方法的單元測試是最低級測試。框架
所謂單元測試(unit testing),就是開發者編寫的一小段代碼,用於對軟件中的最小單元進行檢查和驗證,其通常驗證對象是一個函數或者一個類。一般而言,一個單元測試是用於判斷某個特定條件(或者場景)下某個特定函數的行爲。編輯器
對於我我的來講,主要是防止本身犯低級錯誤的,同時也方便修改(BUG修復)而不引入新的問題。能夠放心大膽的重構。簡言之,這個簡單有效的技術就是爲了令代碼變得更加完美。ide
能夠概括爲如下幾個理由。函數
對單元測試存在的誤解,如:單元測試屬於測試工做,應該由測試人員來完成,因此單元測試不屬於開發人員的職責範圍。工具
答:雖然單元測試雖然叫作"測試",但實際屬於開發範疇,應該由開發人員來作,而開發人員也能從中受益。單元測試
沒有真正意識到單元測試的收益,認爲寫單元測試太費時,不值得。測試
答:在開發時越早發現bug,就能節省更多的時間,下降更多的風險。單元測試先期要編寫測試用例,是須要多耗費些時間,可是後面的調試、自測,均可以經過單元測試處理,不用手工一遍又一遍處理。實際上總時間被減小了。spa
項目經理或技術主管沒有要求寫單元測試,因此不用寫。
答:寫單元測試應該成爲開發人員的一種本能,開發自己就應該包含單元測試。
不知道有單元測試這回事,不知道如何用。通過這篇文檔的說明,就基本知道如何處理單元測試。
經常使用單元測試框架:MSTest (Visual Studio官方)、XUnit 和 NUnit。
(如下主要講解MSTest 和NUnit的使用,XUnit操做和NUnit操做基本相似)
新建一個Solution,並添加項目UnitTestDemo(用於編寫被測試的項目)
在該工程中添加UnitTestClass類,並書寫一個靜態的GetTriangle(string[] sideArr) 函數用來返回一個三角形的類型。
namespace UnitTest { public class UnitTestClass { /// <summary> /// 獲取三角形類型. /// </summary> /// <param name="sideArr">三角形三邊長度數組.</param> /// <returns>返回三角形類型名稱.</returns> public static string GetTriangle(string[] sideArr) { string result = string.Empty; int a = int.Parse(sideArr[0]); int b = int.Parse(sideArr[1]); int c = int.Parse(sideArr[2]); if (a + b > c && a + c > b && b + c > a) { if (a == b && a == c) { result = "等邊三角形"; } if (a == b || a == c || b == c) { result = "等腰三角形"; } else { result = "通常三角形"; } } else { result = "不構成三角形"; } return result; } } }
新建好測試項目以後,你會獲得一個UnitTest1測試類模板,即一個帶有[TestClass] attribute標記的類和一個帶有[TestMethod] attribute標記的空方法public void TestMethod1()。
單元測試項目沒法自動訪問它正在測試的類庫。 能夠經過添加對類庫項目的引用來提供測試庫訪問權限。 爲此,請右鍵單擊UnitTestProject1項目,而後依次選擇「添加」 > 「引用」。在「引用管理器」對話框中,而後選擇 UnitTestDemo項目,以下圖中所示。
在UnitTestDemoTests項目中添加UnitTestDemo項目的引用,如今咱們的solution就具備了下圖所示的目錄結構。
5. 在UnitTestDemoTests項目中的UnitTest1類中,將模板提供的樣本單元測試代碼替換爲如下代碼:
using UnitTest; using System; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace UnitTestDemoTests { [TestClass] public class UnitTest1 { [TestMethod()] public void GetTriangle_Test() { string[] sideArr = {"5", "5", "5"}; Assert.AreEqual("等邊三角形", UnitTestClass.GetTriangle(sideArr)); } } }
6. 生成UnitTestDemoTests測試項目,在生成項目後,測試項將出如今測試資源管理器中。 若是測試資源管理器窗口不可見,請選擇頂級 Visual Studio 菜單上的「測試」,而後依次選擇「窗口(Windows)」、「測試資源管理器(Ctrl + E,T9)」,如圖所示。
7. 在測試資源管理器上能夠看到剛剛所寫的測試方法,這樣在GetTriangle_Test單擊右鍵選擇「運行所選定的測試」就能夠在Test Explorer裏看到單元測試的運行結果,以下圖所示。
能夠看到,咱們在單元測試中提供的例子的指望是輸出「等邊三角形」,運行結果倒是「等腰三角形」。再看一看 GetTriangle() 函數的代碼,原來是在對在判斷三邊數值是等邊三角形以後沒有使用 else if 又用 if 判斷爲等腰三角形了。經過這個簡單的單元測試就可以發現一些意向不到的錯誤。不要覺得這裏的bug很低級,相似的狀況確實會在現實中發生。
8. 把上面的錯誤更正後,再次運行TestMethod1()就會獲得測試已經過的結果,如圖所示。
建立單元測試項目和測試方法,除了以上經過手動建立單元測試項目和根據你的要求進行編寫測試用例以外,還能夠從你的項目的方法上直接生成單元測試項目和單元測試存根,那樣操做更加方便,速度也會更快一些。
這裏涉及測試框架的選擇,MSTest是VS自帶的測試框架。新的MS TEST如今是經過Nuget的包發佈了,目前MS發佈了兩個版本:
- MS TEST V1:V1的版本依賴於一個包: MSTest.TestFramework
- MS TEST V2:V2的版本依賴於兩個包: MSTest.TestFramework 和 MSTest.TestAdapter
這兩個版本使用起來仍是大同小異的,MSTest v2 主要是爲了.net core準備的,固然也能夠在.net framework上運行,而且在v1上新加入了一些擴展。
你使用的單元測試框架和 Visual Studio IntelliSense 將指導你完成爲代碼項目的單元測試編寫代碼。 若要在測試資源管理器中運行,大多數框架要求你添加特定的屬性來識別單元測試方法。 框架還提供了一種方法,一般經過斷言語句或方法屬性,來指示測試方法是否已經過或失敗。 其餘屬性標識可選的安裝方法,即在類初始化時和每一個測試方法和每一個拆卸方法以前的安裝方法,這些拆卸方法在每一個測試方法以後和類被銷燬以前運行。
AAA(準備、執行、斷言)模式是編寫待測試方法的單元測試的經常使用方法:
[TestMethod()] public void GetTriangle_Test() { // arrange string[] sideArr = { "5", "5", "5" }; // 準備傳給待測試方法的數據 string expected = "等邊三角形"; // act var actual = UnitTestClass.GetTriangle(sideArr); // 調用測試方法 // assert Assert.AreEqual(expected, actual); // 驗證待測試方法的執行結果是否與預期相同 }
在某些狀況下(例如經過網絡獲取數據),經常不但願程序卡住而佔用太多時間,經過設置測試方法的超時時間,來測試一個方法是否在預期時間內執行。
[TestMethod()] [Timeout(2000)] // 毫秒 要在單個測試方法上設置超時時間 public void GetTriangle_Test() { ... }
[TestMethod()] [Timeout(TestTimeout.Infinite)] // 毫秒 將超時時間設置爲容許的最大值 public void GetTriangle_Test() { ... }
什麼是參數化測試?
答:簡單的說,就是一樣的邏輯,根據輸入參數不一樣,給出不一樣的結果。由於只是參數不一樣,因此並不但願把測試方法寫多遍,可是又但願對每一個參數的測試成爲一個獨立的測試用例。舉例說,假定我有一個數學計算的方法是把兩個整數相加求和,我但願證實這個方法對於任意兩個數都是經過的。
在MSTest中能夠經過DataRow Attribute 來指定測試用例的參數,實現參數化測試:
/// <summary> /// 相加(待測試方法) /// </summary> /// <param name="num1">數值1</param> /// <param name="num2">數值2</param> /// <returns>計算結果</returns> public static int Add(int num1, int num2) { return Math.Abs(num1 + num2); }
/// <summary> /// 測試方法 /// </summary> [TestMethod()] [DataRow(10, 20)] [DataRow(-2, -5)] [DataRow(1, -2)] [DataRow(5, null)] public void Add_Test(int num1, int num2) { Assert.AreEqual(UnitTestClass.Add(num1, num2), num1 + num2); }
測試了全部可能的狀況,以達到更好的覆蓋率。上方給出示例Add方法的單元測試運行測試結果以下圖所示。
測試結果:測試結果指出對兩個數相加操做的方法,目標方法還取了絕對值,與相應結果不符。
可使用測試資源管理器爲你的測試啓動調試會話。 使用 Visual Studio 調試程序能夠無縫地逐句得使你在單元測試和所測試項目之間來回反覆。 若要開始調試:
在 Visual Studio 編輯器中,在想要調試的一個或多個測試方法中設置斷點。
在測試資源管理器中,選擇測試方法,而後點擊右鍵從快捷菜單選擇「調試選定的測試」。
3. 進入調試模式
F5 繼續。
F10 執行下一行代碼,但不執行任何函數調用。
F11 在執行進入函數調用後,逐條語句執行代碼。
Shift + F11 執行當前執行點所處函數的剩餘行。
Shift + F5 中止運行程序中的當前應用程序。可用於「中斷」模式和「運行」模式。
1)下載安裝NUnit插件
咱們在VS中選擇工具菜單欄下的擴展和更新,選擇聯機並在搜索框中輸入NUnit。有2個版本的Nunit適配器,分別爲NUnit 3.x(最新版爲3.4.1)和NUnit 2.x(最新版爲2.6.4),都支持Visual Studio 2012+。若想在VS2010中集成,須要安裝NUnit 2.6.4安裝包(可在官網下載)與VS2010 NUnit整合插件下載,下載安裝完畢就能在 VS2010 的視圖=>其餘窗口中看到 Visual Nunit (或使用快捷鍵Ctrl + F7),打開該視圖,將之拖到合適的位置。
2)建立NUnit單元測試項目
未完待續..
7. 中止實時單元測試:
IntelliTest 瀏覽你的 .NET 代碼,以生成測試數據和單元測試套件。 對於代碼中的每一個語句,將生成執行該語句的測試輸入。 爲代碼中的每一個條件分支執行案例分析。 例如,分析 if 語句、斷言和可能引起異常的全部操做。 此分析用於爲你的每一個方法生成參數化單元測試的測試數據,從而建立具備較高代碼覆蓋率的單元測試。
當你運行 IntelliTest 時,你可輕鬆看到哪些測試會失敗,並可添加任何須要的代碼來修復它們。 你可選擇要保存到測試項目中的已生成測試,以提供迴歸套件。 當你更改代碼時,從新運行 IntelliTest,以使生成的測試與你的代碼更改同步。
IntelliTest 僅可用於 C# 且不支持 x64 配置。
若要生成單元測試,你的類型必須是公共類。 不然,先建立單元測試,而後再生成它們。
在 Visual Studio 中打開解決方案。 而後打開包含你要測試的方法的類文件。
在代碼中右鍵單擊一種方法並選擇「建立 IntelliTest」,爲方法中的代碼建立生成單元測試項目。
接受默認格式以生成測試,或更改項目和測試的命名方式。 你能夠建立新的測試項目或將你的測試保存到現有項目。
3. 建立測試項目成功以後,選擇上圖中「運行 IntelliTest」,爲方法中的代碼運行IntelliTest單元測試項目。
IntelliTest 使用不一樣的輸入屢次運行你的代碼。 每次運行都會在表中表示出來,顯示輸入測試數據以及產生的輸出或異常。
要爲一個類中的全部公共方法生成單元測試,只需右鍵單擊類而不是特定的方法。 而後選擇「運行 IntelliTest」。 使用「瀏覽結果」窗口中的下拉列表,顯示類中每一個方法的單元測試和輸入數據。
對於經過的測試,檢查結果列中報告的結果是否與你對代碼的預期要求匹配。 對於失敗的測試,根據須要修復你的代碼。 而後從新運行 IntelliTest 來驗證修復。