qileilove

          blog已經(jīng)轉(zhuǎn)移至github,大家請(qǐng)?jiān)L問(wèn) http://qaseven.github.io/

          走進(jìn)單元測(cè)試三:實(shí)戰(zhàn)單元測(cè)試

           前兩篇文章講解了一些關(guān)于單元測(cè)試的基本理論知識(shí),接下來(lái)我們應(yīng)該理論聯(lián)系實(shí)踐,在實(shí)踐中體會(huì)單元測(cè)試帶給我們的便利!

            環(huán)境:VS2008,2010版本!

            目錄:
            1.前言
            2.單元測(cè)試框架
            3.斷言(Assert)
            4.測(cè)試異常
            5.忽視測(cè)試
            6.數(shù)據(jù)驅(qū)動(dòng)測(cè)試
            7.單元測(cè)試的利器 → Moles技術(shù)

            1.前言

            一個(gè)完整的測(cè)試必須符合以下幾點(diǎn):

            A)  考慮到各種情況,準(zhǔn)備測(cè)試所需要的各種數(shù)據(jù),這一步是測(cè)試的關(guān)鍵所在!

            B)  調(diào)用要測(cè)試的方法!

            C)  驗(yàn)證被測(cè)試方法的行為跟預(yù)期的是否一致!

            D)  完成驗(yàn)證測(cè)試之后清理各種資源!

            2.單元測(cè)試框架

            測(cè)試框架的DLL文件名為: Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll

            在VS自動(dòng)創(chuàng)建單元測(cè)試項(xiàng)目就會(huì)自動(dòng)引用這個(gè)DLL了!

            測(cè)試類的基本結(jié)構(gòu)如圖:

            基本的測(cè)試類結(jié)構(gòu)就是這樣的!

            3.斷言(Assert)

            在單元測(cè)試代碼里斷言是無(wú)處不在的,我們應(yīng)該合理的使用斷言來(lái)驗(yàn)證數(shù)據(jù)!

            它是一個(gè)靜態(tài)類,主要有下面幾種方法用來(lái)驗(yàn)證函數(shù)的結(jié)果跟我的預(yù)期是否一致!

            ① Assert.AreEqual

            主要是驗(yàn)證函數(shù)產(chǎn)生的影響值或返回的值跟預(yù)期是否一致,這個(gè)方法不適合驗(yàn)證返回的數(shù)據(jù)集以及集合之類的數(shù)據(jù),主要針對(duì)字符串,數(shù)字等等的單一類型,它還有個(gè)泛型重載,這個(gè)是比較好的,建議多使用,它還有第三個(gè)參數(shù),是一個(gè)string型的message,基本上不會(huì)用到!

            ☆ Note:不要把參數(shù)的含義搞混,第一個(gè)參數(shù)是你的期望值(Except),第二個(gè)參數(shù)是函數(shù)返回或影響程序產(chǎn)生的實(shí)際值(Actual),不要把兩個(gè)顛倒過(guò)來(lái),因?yàn)槿绻\(yùn)行正確沒(méi)有什么大礙,如果運(yùn)行產(chǎn)生錯(cuò)誤,有的時(shí)候就會(huì)看錯(cuò)掉,造成判斷失誤,要注意了,這是一個(gè)規(guī)范!

            例子:

            Assert.AreEqual<string>("a", "a", "cheng xu yuan");

            ② Assert.AreNotEqual

            沒(méi)什么要講的,情況跟上面相反,主要是驗(yàn)證實(shí)際值跟期望值不相等的情況!

          ③ Assert.AreSame

            判斷實(shí)際值跟預(yù)期值的類型是否一致!

            ④ Assert.AreNotSame

            跟上面正好相反,測(cè)試類型不一致!

            ⑤ Assert.IsNotNull,Assert.IsNull,Assert.IsTrue,Assert.IsFalse

            看這些方法名就知道什么意思了!

            ⑥ Assert.IsInstanceOfType,Assert.IsNotInstanceOfType

            判斷指定的對(duì)象是否是指定的類型!

            ⑦ Assert.Fail

            迫使斷言失敗,不管前面的斷言是否都成功了,但測(cè)試結(jié)果是錯(cuò)誤的,因?yàn)槲覐?qiáng)制斷言失敗了!

            總結(jié):一個(gè)好的測(cè)試案例,里面的斷言至少是大于一個(gè)的,這樣才能驗(yàn)證數(shù)據(jù)的準(zhǔn)確性,保證驗(yàn)證數(shù)據(jù)的嚴(yán)謹(jǐn)性!

            例:如果實(shí)際值是個(gè)DataSet一般測(cè)試流程為:①判斷是否為“null” → ②判斷是否為“Empty”(驗(yàn)證是否有數(shù)據(jù)) →③ 接下來(lái)再驗(yàn)證數(shù)據(jù)的一致性,所以驗(yàn)證DataSet的基本流程就是這樣的!

          /// <summary>
          /// Modify.
          /// </summary>
          [TestMethod()]
          [RollBack()]
          public void UpdateBondAssessApplicationConfiguration_ModifyData_DataUpdated() //注意命名規(guī)范,下一篇會(huì)著重講解!
          {
          AssessApplicationConfigurationDataSet assessConfigurationDataSet = target.GetBondAssessApplicationConfiguration();
          assessConfigurationDataSet.CM_LookupConfiguration[0].Description = "This is my modify";
          AssessApplicationConfigurationDataSet actual = target.UpdateBondAssessApplicationConfiguration(assessConfigurationDataSet);
          AssessApplicationConfigurationDataSet newAssessAppDataSet = target.GetBondAssessApplicationConfiguration();

          Assert.IsNotNull(actual);                                                                       //第一步 驗(yàn)證是否為Null
          Assert.IsTrue(actual.CM_LookupConfiguration.Rows.Count > 0);                                    //第二步 驗(yàn)證是否為Empty
          Assert.IsTrue(newAssessAppDataSet.CM_LookupConfiguration[0].Description == "This is my modify");//第三步 驗(yàn)證數(shù)據(jù)的一致性
          Assert.IsTrue(CompareToTable(newAssessAppDataSet.CM_LookupConfiguration, actual.CM_LookupConfiguration));
          }

            4.測(cè)試異常 → ExpectedException(異常屬性)

            當(dāng)代碼中有拋出異常的情況時(shí),我們應(yīng)該對(duì)這個(gè)異常的準(zhǔn)確性進(jìn)行測(cè)試,首先要捕獲這個(gè)異常,然后再跟我預(yù)期定義的異常進(jìn)行比較就行了!

            在VS自帶的測(cè)試框架中提供了處理異常的測(cè)試!

            這個(gè)異常屬性有兩個(gè)構(gòu)造函數(shù)重載:

            第一個(gè)參數(shù):函數(shù)中出現(xiàn)異常的類型 →  [ExpectedException(typeof(NullReferenceException))]

            第二個(gè)參數(shù):異常所提示的信息(Message) → [ExpectedException(typeof(NullReferenceException),"Don't is null.")]

            總結(jié):在測(cè)試一些非法數(shù)據(jù),邊界值,異常測(cè)試是非常有用的,一旦發(fā)現(xiàn)異常,后面的一切斷言和代碼將跳過(guò),然后系統(tǒng)將會(huì)把異常和你預(yù)期的異常進(jìn)行比對(duì),一致則表示通過(guò),反之有錯(cuò)誤!

          /// <summary>
          /// Is null.
          /// </summary>
          [TestMethod()]
          [RollBack()]
          [ExpectedException(typeof(NullReferenceException))]  //第一種只定義了異常類型!
          public void UpdateLookupChequeNumberRegion_UpdateChequeNumberRegionAndDataSetIsNull_ThrowException()
          {
          LookupChequeNumberRegionDataSet actual = target.UpdateLookupChequeNumberRegion(null);
          }
          /// <summary>
          /// Add.
          /// </summary>
          [TestMethod()]
          [RollBack()]            //第二種定義了預(yù)期的異常類型還定義了異常信息!
          [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.忽視測(cè)試 → Ignore屬性

            添加這個(gè)屬性表明現(xiàn)在這個(gè)測(cè)試案例在運(yùn)行時(shí)將不會(huì)被執(zhí)行,跳過(guò)此方法!

          [TestMethod()]
          [Ignore()]        //運(yùn)行單元測(cè)試時(shí)將忽視這個(gè)測(cè)試案例
          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.數(shù)據(jù)驅(qū)動(dòng)測(cè)試

            在上一篇提到過(guò)當(dāng)你的數(shù)據(jù)量很大的時(shí)候,有一種解決方案是采用數(shù)據(jù)驅(qū)動(dòng)測(cè)試,把我們需要用來(lái)測(cè)試的數(shù)據(jù)放在文件中,然后運(yùn)行測(cè)試,讓測(cè)試代碼去讀取文件中的數(shù)據(jù)!

            其實(shí)它也有一定的局限性,所以在合理的場(chǎng)合中合理的使用將減輕我們的工作量,這個(gè)判斷只能給為看官去判斷了!

            當(dāng)前支持Sql Server ,Oracle,CSV,XML等等文件,下面我就介紹下CSV和XML文件的使用方法!

            ①CSV作為數(shù)據(jù)文件

            我們寫一個(gè)簡(jiǎn)單不能再簡(jiǎn)單的的加法運(yùn)算方法來(lái)作為示例:

          public int Add(int numberOne, int numberTwo)
          {
          int one = numberOne;
          int two = numberTwo;
          int three = numberOne + numberTwo;
          return three;
          }

            a) 首先要?jiǎng)?chuàng)建連接字符串,具體步驟如下:

            I,

            II,

            III,

           通過(guò)上面步驟的操作,就會(huì)進(jìn)入選擇文件的界面,按照提示即可完成,當(dāng)然前提你的數(shù)據(jù)文件要準(zhǔn)備好,完成之后會(huì)出現(xiàn)如下代碼:

          /// <summary>
          ///Add 的測(cè)試
          ///</summary>
          [DataSource("Microsoft.VisualStudio.TestTools.DataSource.CSV",
          "|DataDirectory|\\number.csv",
          "number#csv",
          DataAccessMethod.Sequential),  //這個(gè)是連接字符串,你也可以手動(dòng)寫,不要按照上面步驟操作,當(dāng)然要寫對(duì)單詞和“注意文件的路徑”!
          DeploymentItem("MyTest\\number.csv"),
          TestMethod()]
          public void AddTest1()
          {
          Program target = new Program();
          int numberOne = Convert.ToInt32(this.testContextInstance.DataRow["One"]);  //獲取數(shù)據(jù)!
          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);
          }

            點(diǎn)擊運(yùn)行你的測(cè)試,程序會(huì)通過(guò)你設(shè)置的路徑去文件里面一行一行的讀取數(shù)據(jù),然后驗(yàn)證數(shù)據(jù),如果其中有一行數(shù)據(jù)報(bào)錯(cuò),那么整個(gè)測(cè)試也就是失敗了,所以保證數(shù)據(jù)的正確性很重要!

            注意:CSV默認(rèn)會(huì)以Excel的方式打開(kāi),但是它里面的數(shù)據(jù)擺放有一個(gè)規(guī)則,就是以逗號(hào)的形式呈現(xiàn),所以我還是建議大家使用記事本來(lái)添加數(shù)據(jù)!

            ②使用XML作為數(shù)據(jù)文件

            其實(shí)使用方法跟上面的一樣,尤其注意的是你XML文件里面數(shù)據(jù)的格式!

          <table> //一定要設(shè)置根節(jié)點(diǎn),如果不設(shè)置在文件選擇的時(shí)候會(huì)報(bào)錯(cuò)!
          <my>
          <price>1</price>
          <number>1</number>
          <total>1</total>
          </my>
          <my>
          <price>2</price>
          <number>2</number>
          <total>4</total>
          </table>

            注意:怎么來(lái)獲取數(shù)據(jù)呢?Convert.ToInt32(this.testContextInstance.DataRow["price"]) 通過(guò)這樣的方式來(lái)獲取數(shù)據(jù),還有在選擇文件時(shí),要確認(rèn)是否選中了一個(gè)數(shù)據(jù)源文件,這個(gè)不要疏忽了!

            ③使用數(shù)據(jù)庫(kù)作為數(shù)據(jù)文件很簡(jiǎn)單,配置一下連接字符串,設(shè)置一下路徑就好了,在此就不講解了!

            7.單元測(cè)試的利器 → “Mole”技術(shù)

            首先想感謝下項(xiàng)目組的Tian Mi大哥是他把這項(xiàng)技術(shù)帶給我們的,謝謝他的無(wú)私奉獻(xiàn)!

            “Mole”文件的下載地址:http://www.kuaipan.cn/index.php?ac=file&oid=29568238492847207

            ①應(yīng)用環(huán)境:

            所屬模塊依賴于系統(tǒng)的其它模塊,依賴于系統(tǒng)的一些配置環(huán)境,還有就是調(diào)用第三方接口或服務(wù)等等的場(chǎng)景!

            在這樣的場(chǎng)景下我們的測(cè)試是不能直接調(diào)用第三方接口或服務(wù)的,所以我們要制造一個(gè)虛擬的環(huán)境,當(dāng)我們?nèi)フ{(diào)用接口時(shí),Mole技術(shù)會(huì)攔截我們調(diào)用的方法,從而轉(zhuǎn)向我們自己制造的虛擬環(huán)境,那么就不會(huì)直接調(diào)用第三方接口和服務(wù)了!

            ②基本的操作流程不講解了,如果你看了http://www.cnblogs.com/hwade/archive/2010/11/26/Moles.html這篇文章就明白了,我就將一些在寫測(cè)試時(shí)遇到的幾個(gè)小問(wèn)題!

            ③如果“Moles”結(jié)束后,項(xiàng)目編譯的時(shí)候報(bào)錯(cuò),具體的錯(cuò)誤我也不怎么知道了,但是我在網(wǎng)上搜了很久才找到答案的!

            步驟:點(diǎn)擊你的Moles文件,你會(huì)發(fā)現(xiàn)他是個(gè)XML配置文件,修改它的屬性就好了,如:

          <Moles  xmlns=http://schemas.microsoft.com/moles/2010/  DisableCache="true" >  //增加一個(gè)DisableCache = "true"這個(gè)屬性,如果遇到問(wèn)題,基本都是這個(gè)問(wèn)題,這樣解決就Ok了!
          <Assembly Name="Foundation.FinanceManagement.BusinessService"  />
          </Moles>

           ③有“Ref”參數(shù)的方法應(yīng)該怎么寫?

            如果參數(shù)中ref參數(shù),那么就不能按一般的方式寫了,應(yīng)該這樣寫:

            ④Moles的基本語(yǔ)法

            Moles的內(nèi)部原理沒(méi)有明白,只懂的怎么去用它,基本的語(yǔ)法可以模仿上面的寫法!

            因?yàn)槟惆岩粋€(gè)DLL Moles之后并編譯之后會(huì)生成一個(gè)新的DLL,這里面就是虛擬環(huán)境場(chǎng)所,而且類名稱都是以“M”開(kāi)頭的!

            語(yǔ)法:命名空間 + Moles + M + 你Moles掉的類名 + Allinstance + 選擇你要攔截的方法名 = (instance(必填參數(shù),如果方法沒(méi)參數(shù),也必要添個(gè)))  =>

            {

            //里面寫你的邏輯,制造你自己的虛擬環(huán)境,如果方法有返回值,可以自己指定返回值的!

            };

            好了,關(guān)于在實(shí)踐中的單元測(cè)試就這么多了,其實(shí)最重要的還是你考慮測(cè)試的角度要多樣化,就是考慮問(wèn)題要全面,還有代碼的簡(jiǎn)潔性,重構(gòu),封裝等等,下一篇將是對(duì)這方面的著重討論!

          相關(guān)文章:

          走進(jìn)單元測(cè)試二:測(cè)試需要從哪些方面著手

          走進(jìn)單元測(cè)試四:?jiǎn)卧獪y(cè)試背后的思考和感悟


          posted on 2013-08-09 10:48 順其自然EVO 閱讀(223) 評(píng)論(0)  編輯  收藏


          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          <2013年8月>
          28293031123
          45678910
          11121314151617
          18192021222324
          25262728293031
          1234567

          導(dǎo)航

          統(tǒng)計(jì)

          常用鏈接

          留言簿(55)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 金门县| 芜湖市| 新郑市| 新津县| 全州县| 车险| 密山市| 隆尧县| 巩义市| 黑龙江省| 论坛| 石河子市| 巫山县| 乌兰察布市| 华阴市| 卢湾区| 阿拉尔市| 星子县| 玛沁县| 长丰县| 南华县| 黄浦区| 闽清县| 桑植县| 资阳市| 东辽县| 宝丰县| 浠水县| 洛南县| 施秉县| 西乡县| 衡南县| 濮阳县| 松江区| 宜良县| 鸡东县| 玛曲县| 周至县| 钟山县| 曲周县| 湾仔区|