zoukankan      html  css  js  c++  java
  • 单元测试实例

    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的基本流程就是这样的!   

    复制代码
     1     /// <summary>
    2      /// Modify.
    3     /// </summary>
    4 [TestMethod()]

    5 [RollBack()]
    6 public void UpdateBondAssessApplicationConfiguration_ModifyData_DataUpdated() //注意命名规范,下一篇会着重讲解!
    7 {
    8 AssessApplicationConfigurationDataSet assessConfigurationDataSet = target.GetBondAssessApplicationConfiguration();
    9 assessConfigurationDataSet.CM_LookupConfiguration[0].Description = "This is my modify";
    10 AssessApplicationConfigurationDataSet actual = target.UpdateBondAssessApplicationConfiguration(assessConfigurationDataSet);
    11 AssessApplicationConfigurationDataSet newAssessAppDataSet = target.GetBondAssessApplicationConfiguration();
    12
    13 Assert.IsNotNull(actual); //第一步 验证是否为Null
    14 Assert.IsTrue(actual.CM_LookupConfiguration.Rows.Count > 0); //第二步 验证是否为Empty
    15 Assert.IsTrue(newAssessAppDataSet.CM_LookupConfiguration[0].Description == "This is my modify");//第三步 验证数据的一致性
    16 Assert.IsTrue(CompareToTable(newAssessAppDataSet.CM_LookupConfiguration, actual.CM_LookupConfiguration));

    17 }
    复制代码

     

     4.测试异常 → ExpectedException(异常属性)                

        当代码中有抛出异常的情况时,我们应该对这个异常的准确性进行测试,首先要捕获这个异常,然后再跟我预期定义的异常进行比较就行了!

        在VS自带的测试框架中提供了处理异常的测试!

                 这个异常属性有两个构造函数重载:

        第一个参数:函数中出现异常的类型 →  [ExpectedException(typeof(NullReferenceException))]

        第二个参数:异常所提示的信息(Message) → [ExpectedException(typeof(NullReferenceException),"Don't is null.")]

          总结:在测试一些非法数据,边界值,异常测试是非常有用的,一旦发现异常,后面的一切断言和代码将跳过,然后系统将会把异常和你预期的异常进行比对,一致则表示通过,反之有错误!    

    复制代码
     1      /// <summary>
    2      /// Is null.
    3      /// </summary>
    4 [TestMethod()]

    5 [RollBack()]
    6 [ExpectedException(typeof(NullReferenceException))] //第一种只定义了异常类型!
    7 public void UpdateLookupChequeNumberRegion_UpdateChequeNumberRegionAndDataSetIsNull_ThrowException()
    8 {
    9 LookupChequeNumberRegionDataSet actual = target.UpdateLookupChequeNumberRegion(null);
    10 }
    11
    12 /// <summary>
    13      /// Add.
    14      /// </summary>
    15 [TestMethod()]

    16 [RollBack()]            //第二种定义了预期的异常类型还定义了异常信息!
    17 [ExpectedException(typeof(BusinessException), "The category and code combination you have entered already exist. Please enter a different category and code combination.")]
    18 public void UpdatePolicyConsideration_AddPolicyTheCODEIsSame_ThrowException()
    19 {
    20 string newGUID = Guid.NewGuid().ToString();
    21 CodeTableDataSet expectedDataSet = target.GetPolicyConsideration();
    22 expectedDataSet.T_IC_CODE.AddT_IC_CODERow(GetNewRow(expectedDataSet, null, ref newGUID));
    23 CodeTableDataSet actual = target.UpdatePolicyConsideration(expectedDataSet);
    31 }
    复制代码

       

     5.忽视测试 → Ignore属性                      

        添加这个属性表明现在这个测试案例在运行时将不会被执行,跳过此方法!    

    复制代码
     1      [TestMethod()]
    2 [Ignore()] //运行单元测试时将忽视这个测试案例
    3 public void GetBondDebt_InputValidClientID_RecordFound()

    4 {
    5 int clientCoreID = GetClientIDForSomeCondition();
    6 DebtDataSet actual = target.GetBondDebt(clientCoreID);
    7
    8 Assert.IsNotNull(actual);
    9 Assert.IsTrue(actual.Debt.Rows.Count > 0);
    10 Assert.IsTrue(CompareToDataSetAndList(actual, clientCoreID));
    11 }
    复制代码

      

     6.数据驱动测试                                  

        在上一篇提到过当你的数据量很大的时候,有一种解决方案是采用数据驱动测试,把我们需要用来测试的数据放在文件中,然后运行测试,让测试代码去读取文件中的数据!

        其实它也有一定的局限性,所以在合理的场合中合理的使用将减轻我们的工作量,这个判断只能给为看官去判断了!

        当前支持Sql Server ,Oracle,CSV,XML等等文件,下面我就介绍下CSV和XML文件的使用方法!

        也可以参照园子里面的博文:

        http://www.cnblogs.com/zhijianliutang/archive/2011/12/15/2289398.html

        http://www.cnblogs.com/heqichang/archive/2011/10/08/2202441.html

        ①CSV作为数据文件

          我们写一个简单不能再简单的的加法运算方法来作为示例: 

    复制代码
    1      public int Add(int numberOne, int numberTwo)
    2 {
    3 int one = numberOne;
    4 int two = numberTwo;
    5 int three = numberOne + numberTwo;
    6 return three;
    7 }
    复制代码

           a) 首先要创建连接字符串,具体步骤如下:        

            I,  

            II,

            III,

            通过上面步骤的操作,就会进入选择文件的界面,按照提示即可完成,当然前提你的数据文件要准备好,完成之后会出现如下代码:      

    复制代码
     1     /// <summary>
    2      ///Add 的测试
    3      ///</summary>
    4 [DataSource("Microsoft.VisualStudio.TestTools.DataSource.CSV",

    5 "|DataDirectory|\number.csv",
    6 "number#csv",
    7 DataAccessMethod.Sequential), //这个是连接字符串,你也可以手动写,不要按照上面步骤操作,当然要写对单词和“注意文件的路径”!
    8 DeploymentItem("MyTest\number.csv"),
    9 TestMethod()]
    10 public void AddTest1()
    11 {
    12 Program target = new Program();
    13 int numberOne = Convert.ToInt32(this.testContextInstance.DataRow["One"]);  //获取数据!
    14 int numberTwo = Convert.ToInt32(this.testContextInstance.DataRow["Two"]); ;
    15 int expected = Convert.ToInt32(this.testContextInstance.DataRow["Except"]);
    16 int actual = target.Add(numberOne, numberTwo);
    17 Assert.AreEqual(expected, actual);
    18 }
    复制代码

           点击运行你的测试,程序会通过你设置的路径去文件里面一行一行的读取数据,然后验证数据,如果其中有一行数据报错,那么整个测试也就是失败了,所以保证数据的正确性很重要!

           注意:CSV默认会以Excel的方式打开,但是它里面的数据摆放有一个规则,就是以逗号的形式呈现,所以我还是建议大家使用记事本来添加数据!

           

        ②使用XML作为数据文件

          其实使用方法跟上面的一样,尤其注意的是你XML文件里面数据的格式!      

    复制代码
     1     <table> //一定要设置根节点,如果不设置在文件选择的时候会报错!   
    2 <my>
    3 <price>1</price>
    4 <number>1</number>
    5 <total>1</total>
    6 </my>
    7 <my>
    8 <price>2</price>
    9 <number>2</number>
    10 <total>4</total>
    11 </my>
    12 </table>
    复制代码

          注意:怎么来获取数据呢?Convert.ToInt32(this.testContextInstance.DataRow["price"]) 通过这样的方式来获取数据,还有在选择文件时,要确认是否选中了一个数据源文件,这个不要疏忽了!

        ③使用数据库作为数据文件很简单,配置一下连接字符串,设置一下路径就好了,在此就不讲解了!

      

     7.单元测试的利器 → “Mole”技术                    

        首先想感谢下项目组的Tian Mi大哥是他把这项技术带给我们的,谢谢他的无私奉献!

        园子里面也有一篇精华文章,讲解了基本用法,链接为:http://www.cnblogs.com/hwade/archive/2010/11/26/Moles.html

        “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配置文件,修改它的属性就好了,如:      

    1       <Moles  xmlns="http://schemas.microsoft.com/moles/2010/"  DisableCache="true" >  //增加一个DisableCache = "true"这个属性,如果遇到问题,基本都是这个问题,这样解决就Ok了!
    2       <Assembly Name="Foundation.FinanceManagement.BusinessService" />
    3       </Moles>

        

        ③有“Ref”参数的方法应该怎么写?

          如果参数中ref参数,那么就不能按一般的方式写了,应该这样写:

        ④Moles的基本语法

          Moles的内部原理没有明白,只懂的怎么去用它,基本的语法可以模仿上面的写法!

          因为你把一个DLL Moles之后并编译之后会生成一个新的DLL,这里面就是虚拟环境场所,而且类名称都是以“M”开头的!

          语法:命名空间 + Moles + M + 你Moles掉的类名 + Allinstance + 选择你要拦截的方法名 = (instance(必填参数,如果方法没参数,也必要添个))  =>

             {

                //里面写你的逻辑,制造你自己的虚拟环境,如果方法有返回值,可以自己指定返回值的!

             };

      

      好了,关于在实践中的单元测试就这么多了,其实最重要的还是你考虑测试的角度要多样化,就是考虑问题要全面,还有代码的简洁性,重构,封装等等,下一篇将是对这方面的着重讨论!

  • 相关阅读:
    Ionic3 UI组件之 autocomplete
    Ionic项目中如何使用Native Camera
    AD RMS企业文件版权管理
    利用WSUS部署更新程序
    远程桌面web连接
    文件服务器的管理
    域用户配置文件
    无需转化直接使用ESD映像文件安装系统简明教程
    Windows DHCP备份还原命令
    Bitlocker驱动器加密使用
  • 原文地址:https://www.cnblogs.com/luyujie/p/3247430.html
Copyright © 2011-2022 走看看