近期應項目須要,筆者瘋狂學習UWP項目測試的知識,確實學習到了很多關於測試方面的知識,等有時間會好好地記錄下測試的學習成果。OK,回到主題,在筆者作項目測試的過程當中把本身遇到的坑都簡單的記錄了下來,而且寫了個關於測試的Demo,傳送門。下面簡單地筆者的初入測試門檻的經驗!ios
首先上環境:git
使用到的測試框架:MSTest 提供的 UnitTestFramework + 微軟 Microsoft BigPark Studios
團隊開發的 SimpleStub
Mock框架。github
處於筆者的水平限制,筆者前後嘗試了 NUnit
、XUnit
等多款測試框架可是效果並非太好,其中 NUnit
彷佛對 UnitTestProject
(單元測試應用)並不太友好(多半是筆者水平的問題,若是有Dalao能教下我NUnit與UWP的集成請私信),網上的dalao們使用 XUnit
多數是基於 ClassLibrary
的項目,而筆者嘗試的時候發現系統沒法直接調用 ClassLibrary
所書寫的測試 ,須要加載 Runner
,有些小麻煩,不過應該也是能用的。最終,多番嘗試後筆者敲定了使用 MSTest
+ SimpleStub
這兩款框架(都是來自微軟,相信與UWP兼容性不錯)。框架
MSTest比較簡單,上述的MSDN傳送門對應的網頁有詳細的指導,而 SampleStub
則須要注意挺多的,筆者將本身在使用過程當中踩的一些可能比較常見的坑記錄了下來,下面上筆者記錄的小坑:函數
摘自筆者Demo項目的README:單元測試
做爲一個剛入測試的小菜雞,做者在結合使用這兩個框架的時候也遇到了不少坑,下面簡單列舉一些萌新們可能會踩的坑:學習
- UWP 新建一個UnitTest項目?
答:UWP 的單元測試項目優選
單元測試應用
類型的項目,即新建一個單元測試應用
的項目,而且在其中書寫本身的測試測試
- 爲何在新建的UnitTestProject內新建測試文件不會在測試列表中顯示?
答:測試文件目前使用的是註解機制,其中對做爲TestFixture的測試類以及測試方法都是有訪問權限要求的,即必須都爲
public
的 ,而且測試方法Method
必須爲public void
類型的。spa
測試經常使用的東西:
Assert
類的諸多方法,Such as:AreEqual
AreSame
IsTrue
等code如何在目前的Unit測試引入Mock框架?
答:目前的狀況,做者嘗試過許多框架,出於做者水平,這些框架(NUnit Template 不支持、XUnit 換成Library沒法識別測試)在做者的UWP上表現都不太好。目前發現表現最好的是微軟去年年底推出的
SimpleStub
框架,而後做者也推薦使用這個,由於做者我的認爲這個是目前與MSTest
兼容最好的Mock框架。
SimpleStub
如何使用?答:Nuget -> download SimpleStub nuget package 。而後環境就已經搭建好了,選擇你的測試項目進行生成,此時框架會自動在編譯期間在項目obj目錄下生成一個
SimpleStub.generate.cs
的文件。利用這個文件生成一個StubXxxx
的Mock對象進而實現測試,詳細用法見樣例代碼(UnitTestProject1
內的TestUserMagr.cs
)Tips:
- 這裏補充說明下,若是項目生成後在obj目錄下沒找到
SimpleStub.generate.cs
文件,說明生成SimpleStub.generate.cs
文件失敗了,此時應該去查看Console(輸出控制檯)的輸出內容,挖掘出錯誤的緣由,解決異常後從新生成下便可!
SimpleStub
框架爲咱們生成的 StubXxx
Mock對象的一些方法構建,由於這與構建的Mock對象的 MockBehavior
息息相關,詳細請見示例代碼最後,上筆者Demo中測試的部分代碼:
namespace UnitTestProject1 { [TestClass] public class TestUserMagr { // 待測試對象-> uMagr Mock對象->uMagr.UDao(IUserDao) private UserMagr uMagr; [TestInitialize] public void BeforeTestInitialize() { uMagr = new UserMagr(); } [TestMethod] public void TestCallSequence() { // 新建mock對象 var stub = new StubIUserDao(MockBehavior.Strict) .CreateUser((p2) => { return null == p2 ? 0 : 1; }, Times.Once)// 限定最多調用一次 .CreateUser((p2) => { return null == p2 ? 0 : 1; }, Times.Twice)// 限定最多調用兩次 .CreateUser((p2) => { return null == p2 ? 0 : 1; }, Times.Forever);// 解除調用次數上限設置 // 若是不執行上述最後一行,那麼stub對象只能執行CreateUser 兩次(取決於最後一條的限定),執行超出次數會拋異常 // 將Mock對象賦值給依賴對象,從而解除依賴對象對測試的干預 uMagr.UDao = stub; // 從這開始執行測試 相似 EasyMock->replayAll(); Assert.AreEqual(1, uMagr.CreateUser(new User() { Username = "123", Password = "123" })); Assert.AreEqual(1, uMagr.CreateUser(new User() { Username = "123", Password = "123" })); Assert.AreEqual(1, uMagr.CreateUser(new User() { Username = "123", Password = "123" })); } [TestMethod] public void TestMethod_WithReturnType_WithParameters()// 測試Mock對象的函數帶參數的調用 { // 設置一些初始變量 int Expect = 1; string Username = null; string Password = null; // 用於判斷是否修改的對象 User user = new User() { Username = Username, Password = Password }; // 開始構建Mock var stub = new StubIUserDao() .CreateUser((u) => { user = u; return Expect; }); uMagr.UDao = stub; // replayAll() Assert.AreEqual(Expect, uMagr.CreateUser(new User() { Username = "test" })); Assert.AreEqual("test", user.Username); } [TestMethod] public void TestThatMethodStubCanBeOverwritten()// 測試Mock對象的方法是否支持重寫 { // 構建一個Mock對象 var stub = new StubIUserDao() .CreateUser(u => 1); // 重寫其調用的方法,若是須要重寫則須要加上overwrite:true,不然將不會重寫 stub.CreateUser(u => 2, overwrite: true); uMagr.UDao = stub; // replayAll() Assert.AreEqual(2, uMagr.CreateUser(new User())); } [TestMethod] [ExpectedException(typeof(SimpleStubsException))] public void TestMethod_WithReturnType_WithParameters_DefaultBehavior_Strict()// 展現 MockBehavior爲Strict下的不一樣之處,於下面的method一塊兒比對觀察 { // 構建一個不帶函數定義的Mock對象(存根) var stub = new StubIUserDao(MockBehavior.Strict); uMagr.UDao = stub; // 調用方法的時候,Strict模式下會拋出異常,由於沒有定義調用函數 Assert.AreEqual(0, uMagr.CreateUser(null)); } [TestMethod] public void TestMethod_Void_WithNoParameters_DefaultBehavior_Loose() { // 構建一個不帶函數定義的Mock對象(存根),默認下MockBehavior爲Loose var stub = new StubIUserDao(); uMagr.UDao = stub; // 調用方法的時候,Loose模式下不會拋出異常,而且返回函數返回值的默認值 null | 默認基本類型值 | Assert.AreEqual(0, uMagr.CreateUser(null)); } } }
OK,就先記錄到這!