走進單元測試三:實戰單元測試
前兩篇文章講解了一些關于單元測試的基本理論知識,接下來我們應該理論聯系實踐,在實踐中體會單元測試帶給我們的便利!
環境:VS2008,2010版本!
目錄:
1.前言
2.單元測試框架
3.斷言(Assert)
4.測試異常
5.忽視測試
6.數據驅動測試
7.單元測試的利器 → Moles技術
1.前言
一個完整的測試必須符合以下幾點:
A) 考慮到各種情況,準備測試所需要的各種數據,這一步是測試的關鍵所在!
B) 調用要測試的方法!
C) 驗證被測試方法的行為跟預期的是否一致!
D) 完成驗證測試之后清理各種資源!
2.單元測試框架
測試框架的DLL文件名為: Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll
在VS自動創建單元測試項目就會自動引用這個DLL了!
測試類的基本結構如圖:
基本的測試類結構就是這樣的!
3.斷言(Assert)
在單元測試代碼里斷言是無處不在的,我們應該合理的使用斷言來驗證數據!
它是一個靜態類,主要有下面幾種方法用來驗證函數的結果跟我的預期是否一致!
① Assert.AreEqual
主要是驗證函數產生的影響值或返回的值跟預期是否一致,這個方法不適合驗證返回的數據集以及集合之類的數據,主要針對字符串,數字等等的單一類型,它還有個泛型重載,這個是比較好的,建議多使用,它還有第三個參數,是一個string型的message,基本上不會用到!
☆ Note:不要把參數的含義搞混,第一個參數是你的期望值(Except),第二個參數是函數返回或影響程序產生的實際值(Actual),不要把兩個顛倒過來,因為如果運行正確沒有什么大礙,如果運行產生錯誤,有的時候就會看錯掉,造成判斷失誤,要注意了,這是一個規范!
例子:
Assert.AreEqual<string>("a", "a", "cheng xu yuan");
② Assert.AreNotEqual
沒什么要講的,情況跟上面相反,主要是驗證實際值跟期望值不相等的情況!
③ Assert.AreSame
判斷實際值跟預期值的類型是否一致!
④ Assert.AreNotSame
跟上面正好相反,測試類型不一致!
⑤ Assert.IsNotNull,Assert.IsNull,Assert.IsTrue,Assert.IsFalse
看這些方法名就知道什么意思了!
⑥ Assert.IsInstanceOfType,Assert.IsNotInstanceOfType
判斷指定的對象是否是指定的類型!
⑦ Assert.Fail
迫使斷言失敗,不管前面的斷言是否都成功了,但測試結果是錯誤的,因為我強制斷言失敗了!
總結:一個好的測試案例,里面的斷言至少是大于一個的,這樣才能驗證數據的準確性,保證驗證數據的嚴謹性!
例:如果實際值是個DataSet一般測試流程為:①判斷是否為“null” → ②判斷是否為“Empty”(驗證是否有數據) →③ 接下來再驗證數據的一致性,所以驗證DataSet的基本流程就是這樣的!
/// <summary> Assert.IsNotNull(actual); //第一步 驗證是否為Null |
4.測試異常 → ExpectedException(異常屬性)
當代碼中有拋出異常的情況時,我們應該對這個異常的準確性進行測試,首先要捕獲這個異常,然后再跟我預期定義的異常進行比較就行了!
在VS自帶的測試框架中提供了處理異常的測試!
這個異常屬性有兩個構造函數重載:
第一個參數:函數中出現異常的類型 → [ExpectedException(typeof(NullReferenceException))]
第二個參數:異常所提示的信息(Message) → [ExpectedException(typeof(NullReferenceException),"Don't is null.")]
總結:在測試一些非法數據,邊界值,異常測試是非常有用的,一旦發現異常,后面的一切斷言和代碼將跳過,然后系統將會把異常和你預期的異常進行比對,一致則表示通過,反之有錯誤!
/// <summary> /// Is null. /// </summary> [TestMethod()] [RollBack()] [ExpectedException(typeof(NullReferenceException))] //第一種只定義了異常類型! public void UpdateLookupChequeNumberRegion_UpdateChequeNumberRegionAndDataSetIsNull_ThrowException() { LookupChequeNumberRegionDataSet actual = target.UpdateLookupChequeNumberRegion(null); } /// <summary> /// Add. /// </summary> [TestMethod()] [RollBack()] //第二種定義了預期的異常類型還定義了異常信息! [ExpectedException(typeof(BusinessException), "The category and code combination you have entered already exist. Please enter a different category and code combination.")] public void UpdatePolicyConsideration_AddPolicyTheCODEIsSame_ThrowException() { string newGUID = Guid.NewGuid().ToString(); CodeTableDataSet expectedDataSet = target.GetPolicyConsideration(); expectedDataSet.T_IC_CODE.AddT_IC_CODERow(GetNewRow(expectedDataSet, null, ref newGUID)); CodeTableDataSet actual = target.UpdatePolicyConsideration(expectedDataSet); } |
5.忽視測試 → Ignore屬性
添加這個屬性表明現在這個測試案例在運行時將不會被執行,跳過此方法!
[TestMethod()] [Ignore()] //運行單元測試時將忽視這個測試案例 public void GetBondDebt_InputValidClientID_RecordFound() { int clientCoreID = GetClientIDForSomeCondition(); DebtDataSet actual = target.GetBondDebt(clientCoreID); Assert.IsNotNull(actual); Assert.IsTrue(actual.Debt.Rows.Count > 0); Assert.IsTrue(CompareToDataSetAndList(actual, clientCoreID)); } |
6.數據驅動測試
在上一篇提到過當你的數據量很大的時候,有一種解決方案是采用數據驅動測試,把我們需要用來測試的數據放在文件中,然后運行測試,讓測試代碼去讀取文件中的數據!
其實它也有一定的局限性,所以在合理的場合中合理的使用將減輕我們的工作量,這個判斷只能給為看官去判斷了!
當前支持Sql Server ,Oracle,CSV,XML等等文件,下面我就介紹下CSV和XML文件的使用方法!
①CSV作為數據文件
我們寫一個簡單不能再簡單的的加法運算方法來作為示例:
public int Add(int numberOne, int numberTwo) { int one = numberOne; int two = numberTwo; int three = numberOne + numberTwo; return three; } |
a) 首先要創建連接字符串,具體步驟如下:
I,
II,
III,
通過上面步驟的操作,就會進入選擇文件的界面,按照提示即可完成,當然前提你的數據文件要準備好,完成之后會出現如下代碼:
/// <summary> ///Add 的測試 ///</summary> [DataSource("Microsoft.VisualStudio.TestTools.DataSource.CSV", "|DataDirectory|\\number.csv", "number#csv", DataAccessMethod.Sequential), //這個是連接字符串,你也可以手動寫,不要按照上面步驟操作,當然要寫對單詞和“注意文件的路徑”! DeploymentItem("MyTest\\number.csv"), TestMethod()] public void AddTest1() { Program target = new Program(); int numberOne = Convert.ToInt32(this.testContextInstance.DataRow["One"]); //獲取數據! int numberTwo = Convert.ToInt32(this.testContextInstance.DataRow["Two"]); ; int expected = Convert.ToInt32(this.testContextInstance.DataRow["Except"]); int actual = target.Add(numberOne, numberTwo); Assert.AreEqual(expected, actual); } |
點擊運行你的測試,程序會通過你設置的路徑去文件里面一行一行的讀取數據,然后驗證數據,如果其中有一行數據報錯,那么整個測試也就是失敗了,所以保證數據的正確性很重要!
注意:CSV默認會以Excel的方式打開,但是它里面的數據擺放有一個規則,就是以逗號的形式呈現,所以我還是建議大家使用記事本來添加數據!
②使用XML作為數據文件
其實使用方法跟上面的一樣,尤其注意的是你XML文件里面數據的格式!
<table> //一定要設置根節點,如果不設置在文件選擇的時候會報錯! <my> <price>1</price> <number>1</number> <total>1</total> </my> <my> <price>2</price> <number>2</number> <total>4</total> </table> |
注意:怎么來獲取數據呢?Convert.ToInt32(this.testContextInstance.DataRow["price"]) 通過這樣的方式來獲取數據,還有在選擇文件時,要確認是否選中了一個數據源文件,這個不要疏忽了!
③使用數據庫作為數據文件很簡單,配置一下連接字符串,設置一下路徑就好了,在此就不講解了!
7.單元測試的利器 → “Mole”技術
首先想感謝下項目組的Tian Mi大哥是他把這項技術帶給我們的,謝謝他的無私奉獻!
“Mole”文件的下載地址:http://www.kuaipan.cn/index.php?ac=file&oid=29568238492847207
①應用環境:
所屬模塊依賴于系統的其它模塊,依賴于系統的一些配置環境,還有就是調用第三方接口或服務等等的場景!
在這樣的場景下我們的測試是不能直接調用第三方接口或服務的,所以我們要制造一個虛擬的環境,當我們去調用接口時,Mole技術會攔截我們調用的方法,從而轉向我們自己制造的虛擬環境,那么就不會直接調用第三方接口和服務了!
②基本的操作流程不講解了,如果你看了http://www.cnblogs.com/hwade/archive/2010/11/26/Moles.html這篇文章就明白了,我就將一些在寫測試時遇到的幾個小問題!
③如果“Moles”結束后,項目編譯的時候報錯,具體的錯誤我也不怎么知道了,但是我在網上搜了很久才找到答案的!
步驟:點擊你的Moles文件,你會發現他是個XML配置文件,修改它的屬性就好了,如:
<Moles xmlns=http://schemas.microsoft.com/moles/2010/ DisableCache="true" > //增加一個DisableCache = "true"這個屬性,如果遇到問題,基本都是這個問題,這樣解決就Ok了! <Assembly Name="Foundation.FinanceManagement.BusinessService" /> </Moles> |
③有“Ref”參數的方法應該怎么寫?
如果參數中ref參數,那么就不能按一般的方式寫了,應該這樣寫:
④Moles的基本語法
Moles的內部原理沒有明白,只懂的怎么去用它,基本的語法可以模仿上面的寫法!
因為你把一個DLL Moles之后并編譯之后會生成一個新的DLL,這里面就是虛擬環境場所,而且類名稱都是以“M”開頭的!
語法:命名空間 + Moles + M + 你Moles掉的類名 + Allinstance + 選擇你要攔截的方法名 = (instance(必填參數,如果方法沒參數,也必要添個)) =>
{
//里面寫你的邏輯,制造你自己的虛擬環境,如果方法有返回值,可以自己指定返回值的!
};
好了,關于在實踐中的單元測試就這么多了,其實最重要的還是你考慮測試的角度要多樣化,就是考慮問題要全面,還有代碼的簡潔性,重構,封裝等等,下一篇將是對這方面的著重討論!
相關文章: