本人之前很少使用單元測試,總覺得平時的工作寫得代碼夠多了,單元測試還要再編碼,增加大量工作量,相信不少程序猿也是這么認為吧。
但是我認為,在必要的時候正確運用單元測試,可以大大縮短代碼的調試時間,正所謂磨刀不誤砍柴工,在此建議仍不會單元測試的,還是學一下吧。當然本人在單元測試方面還是菜鳥,無論是雞蛋鮮花都歡迎。
最近公司請微軟的人做了一些關於使用VS2012進行單元測試的小培訓,小生微做筆記,結合朦朧的記憶,在此自行總結,並分享之。廢話少說,先上筆記:
1.先寫單元測試(依我愚見,應該是接口先行,如果有的話) -> 測試失敗 -> 以最小的改動(即編寫實際代碼)使測試通過(而在VS2012中已經不能通過現有項目直接生成測試項目了,我覺得這個功能還是應該保留,微軟總是這副德行,強迫用戶適應他們的產品,但是又不得不適應);
2.不因單元測試而追加功能(代碼),即邏輯不受單元測試影響;
3.改變了代碼的邏輯(增刪改),應及時運行單元測試;
4.在測試方法聲明Attribute —— TestCategory("分類或特征名");
5.在單元測試項目添加Fakes程序集分離外部依賴(如數據庫訪問,獲取配置信息等);
6.初始化單元測試類中的成員等信息,可添加方法並聲明Attribute[TestInitialize](方法需為public);
7.測試自動化。
以下我將通過自己編寫代碼來驗證上述筆記中的部分要點。有些未涉及,以后再嘗試了。
1.新建一個單元測試項目,並添加類XmlSerializationTest,代碼如下:
[TestClass] public class XmlSerializationTest { [TestMethod] public void TestWriteXml() { UserModel user = new UserModel(); XmlSerialization serialization = new XmlSerialization(); bool flag = serialization.WriteXml<UserInifo>(user); Assert.IsTrue(flag); } }
由於我這個項目是對Xml序列化進行測試,因而前提是項目中已存在了一個UserModel類,並且在單元測試項目中添加相應引用
public class UserModel { public string LoginName { get; set; } public string Password { get; set; } }
接下來在編寫實際的代碼,微軟講師建議我們先在測試項目編寫,待通過單元測試后再將代碼移到相應的項目下面。
public class XmlSerialization { public bool WriteXml<T>(T model) { throw new NotImplementedException(); } }
現在整個解決方案結構如下圖所示

保證整個解決方案生成成功之后點擊菜單“測試” -〉 “運行” -〉 “所有測試”,發現測試不通過,於是就按照第一點筆記,以最小改動使測試通過。
修改WriteXml方法為:
public bool WriteXml<T>(T model) { return true; }
運行測試通過。對於返回值為bool的方法,個人建議進行至少兩次Assert,也就是分別對返回true和false進行Assert,因而我們再對WriteXml方法添加一個測試方法,
[TestMethod] public void TestWriteXmlFalse() { Assert.IsFalse(new XmlSerialization().WriteXml<UserModel>(null)); }
運行測試,不通過,所以我得要好好改我的代碼了,在改動當中堅持執行我的第三點筆記,改動代碼及時運行單元測試。
public class XmlSerialization { private string filePath; public XmlSerialization(string filePath) { this.filePath = filePath; } public bool WriteXml<T>(T model, string filePath = null) where T : class { bool result = false; if (model == null) { return result; } if (string.IsNullOrEmpty(filePath)) { filePath = this.filePath; } XmlSerializer serializer = new XmlSerializer(typeof(T)); using (TextWriter tr = new StreamWriter(filePath)) { serializer.Serialize(tr, model); tr.Close(); result = true; } return result; } public T ReadXml<T>(string filePath = null) where T : class { T model = null; if (string.IsNullOrEmpty(filePath)) { filePath = this.filePath; } XmlSerializer serializer = new XmlSerializer(typeof(T)); TextReader tr = null; try { tr = new StreamReader(filePath); model = (T)serializer.Deserialize(tr); } catch { } finally { if (tr != null) { tr.Close(); tr.Dispose(); } } return model; } }
我們發現這個類的構造函數多了一個參數,是對象序列化后保存的路徑,且該類對應的測試類都需要用到,因而我希望在每次測試進行單元測試前先將對象的構建,這就是第六點筆記提供的“聲明Attribute[TestInitialize]”(注意必須是public方法,我用private方法運行測試是不通過)。改造后的測試類如下:
[TestClass] public class XmlSerializationTest { private XmlSerialization serialization; [TestInitialize] public void InitTest() { this.serialization = new XmlSerialization(@"F:\usermodel.seri"); } [TestMethod] public void TestWriteXml() { UserModel user = new UserModel(); bool flag = serialization.WriteXml<UserModel>(user); Assert.IsTrue(flag); Assert.IsFalse(serialization.WriteXml<UserModel>(null)); } [TestMethod] public void TestReadXml() { UserModel user = new UserModel(); user.LoginName = "aa"; serialization.WriteXml<UserModel>(user); UserModel model = serialization.ReadXml<UserModel>(); Assert.IsNotNull(model); Assert.AreEqual(user.LoginName, model.LoginName); //路徑不存在,應返回null UserModel modelnull = serialization.ReadXml<UserModel>(@"F:\notexists.seri"); Assert.IsNull(modelnull); } }
還可以分析測試代碼的覆蓋率,如下圖所示在測試資源管理器點擊“運行”下的相應選項。

居然是100%,真不知道這個東西微軟是怎么分析出來的。

把類XmlSerializationTest移到相應的項目,更改命名空間,在測試項目添加相應引用,測試通過。
將解決方案添加到TFS源碼管理,我這邊是用的是微軟雲TFS免費版。
收工。
VS提供了很多類型的測試,負載、UI等等測試,感覺還是蠻強大的。
