单元测试基础

1.1单元测试的定义

单元测试就是针对一个工做单元设计的测试,这里的“工做单元”是指对一个工做方法的要求。
单元测试是开发者编写的一小段代码,用于检测被测代码的一个很小的、很明确的功能是否正确。一般而言,一个单元测试用于判断某个特定条件(或场景)下某个特定函数的行为。算法

例:
你可能把一个很大的值放入一个有序list中去,而后确认该值出如今list的尾部。或者,你可能会从字符串中删除匹配某种模式的字符,而后确认字符串确实再也不包含这些字符了。
执行单元测试,就是为了证实某段代码的行为和开发者所指望的一致!数据库

//被测方法
  public double Add(double a, double b)
  {
      return a + b;
  }      
  
  //测试方法
  [Test]
  public void AddTest()
  {
      double result = new Calculator().Add(14, 15);
      Assert.AreEqual(30,result);
  }

1.2工做单元

调用系统的一个公共方法到产生一个测试可见的最终结果,其间这个系统发生的行为总称为一个工做单元。咱们经过系统的公共AP和行为就能够观察到一个可见的最终结果,无需查看系统的内部状态。一个最终结果能够是如下任何一种形式。网络

  1. 被调用的公共方法回一个值(一个返回值不为空的函数)
  2. 在方法调用的先后,系统的状态或行为有可见的变化,这种变化无需查询私有状态便可判断。(例如:一个之前不存在的用户能够登入系统,或者一个状态机系统的属性发生变化。)
  3. 调用了一个不受测试控制的第三方系统,这个第三方系统不返回任何值,或者返回值都被忽略。(例如:调用一个第三方日志系统,这个系统不是你编写的,并且你也没有源代码。)

不少人以为被测试的工做单元应该尽量的小。我却不这么看,我认为工做单元这个概念意味着一个单元既能够小到只包含一个方法,也能够大到包括实现某个功能的多个类和函数。若是你的工做单元很大,却可是其最终结果对用户可见度高,易于维护也何尝不是好的测试,相反若是试图把工做单元缩到最小,最后会不得不伪造一堆东西反而会增长测试的复杂度,拔苗助长。函数

2.什么不是单元测试

单元测试实际上是一门很基础也很简单的技术,然而在单元测试实践过程当中,每每会对单元测试产生一些误区,进而写出一些不是单元测试的"单元测试" ,其中常见的主要有如下三种。性能

2.1 跨边界的测试

单元测试背后的思想是,仅测试这个方法中的内容,测试失败时不但愿必须穿过基层代码、数据库表或者第三方产品的文档去寻找可能的答案!
当测试开始渗透到其余类、服务或系统时,此时测试便跨越了边界,失败时会很难找到缺陷的代码。
测试跨边界时还会产生另外一个问题,当边界是一个共享资源时,如数据库。与团队的其余开发人员共享资源时,可能会污染他们的测试结果!单元测试

2.2 不具备针对性的测试

若是发现所编写的测试对一件以上的事情进行了测试,就可能违反了“单一职责原则”。从单元测试的角度来看,这意味着这些测试是难以理解的非针对性测试。随着时间的推移,向类或方法种添加了更多的不恰当的功能后,这些测试可能会变的很是脆弱。诊断问题也将变得极具备挑战性。
如:StringUtility中计算一个特定字符在字符串中出现的次数,它没有说明这个字符在字符串中处于什么位置也没有说明除了这个字符出现多少次以外的其余任何信息,那么这些功能就应该由StringUtility类的其它方法提供!一样,StringUtility类也不该该处理数字、日期或复杂数据类型的功能!测试

2.3 不可预测的测试

单元测试应当是可预测的。在针对一组给定的输入参数调用一个类的方法时,其结果应当老是一致的。有时,这一原则可能看起来很难遵照。例如:正在编写一个日用品交易程序,黄金的价格可能上午九时是一个值,14时就会变成另外一个值。
而好的设计原则就是将不可预测的数据的功能抽象到一个能够在单元测试中模拟(Mock)的类或方法中编码

2.4 集成测试

其实上面三种测试已经到了集成测试的领域。任何测试,若是它运行速度不快,结果不稳定,或者要用到被测试单元的一个或多个真实依赖物,咱们就认为它是集成测试。
集成测试是对一个工做单元进行的测试,这个测试对被测试的工做单元没有彻底的控制,并使用该单元的一个或多个真实依赖物,例如时间、网络、数据库、线程或随机数产生器等。
集成测试自己并非一种坏事,反而其具备和单元测试同样高的地位,可是在实践过程当中咱们把集成测试和单元测试分离开来仍是很重要的。线程

3.优秀的单元测试有哪些特性

单元测试是很是有魔力的魔法,也是一把双刃剑。使用得当,能够颇有效的提升咱们的编码质量,提高研发效率,可是若是使用不恰当亦会浪费大量的时间在测试编码、维护和调试上从而影响代码和整个项目,徒劳而无功!
所以作好单元测试相当重要!而想要作好单元测试,咱们首先应该知道优秀的单元测试有哪些特性。
一个好的单元测试必定是有如下几个特性的
• 自动化
• 完全的
• 可重复的
• 独立的
• 专业的
回顾一下本身之前写过的单元测试问本身几个问题。设计

  1. 它是否是能够自动化一键运行、而且能够重复运行

  2. 几个月后它是否是仍能够运行、而且获得指望的结果

  3. 它是否能够在几分钟内运行结束

  4. 在运行以前你是否不须要须要进行一系列的配置

  5. 每次运行是否可以获得相同的结果

  6. 外部的系统因素是否不会影响你的测试结果

  7. 测试代码是否很简单就能够编写完成

若是针对以上问题有任何一个的回答是“否”,那么你应该好好的思考一下到底如何去作好单元测试。

4. 如何进行单元测试

对于一个方法或者类,乍一看就能找出其隐藏深处的bug是很不容易的,所以在bug挖掘方面一般会有一些经验和套路,来指导咱们更好的进行单元测试。

3.1 测试哪些内容

通常来讲有六个值得测试的具体方面,能够把这六个方面统称为Right-BICEP:

  • Right——结果
    对于单元测试测试而言,首要的也是最明显的任务就是查看所指望的结果是否正确,例如判断一个方法的返回值是否为序列中的最大值......
  • B——边界条件
    找边界条件是作单元测试中最有价值的工做之一,由于bug通常就出如今边界上。关于边界条件2会有详细总结
  • I——检查反向关联
    对于一些方法,咱们可使用反向的逻辑关系来验证它们。例如,你能够用对结果进行平方的方式来检查一个计算平方根的函数,而后测试结果是否和原数据很接近
  • C——交叉检查
    有些时候咱们实现一个问题会有不一样的算法,在生产系统中咱们使用一种算法,而在测试中咱们可使用另外一种算法来验证其结果是否一致。
  • E——强制产生错误条件
    在实际运行过程当中,有时候会发生一些意外的难以免的错误,例如磁盘会满,网络连线会断开.....从而致使程序崩溃。咱们应该在测试中强制引起错误,来测试代码是否可以按照预期处理这些异常。
  • P——是否知足性能条件
    性能一样是咱们测试过程当中须要验证的指标

3.2 注意边界条件

代码中的许多Bug常常出如今边界条件附近,对于边界条件的测试咱们能够从CORRECT七个方面进行考虑

  • 一致性----值是否知足预期的格式
  • 有序性----一组值是否知足预期的排序要求
  • 区间性----值是否在一个合理的最大值最小值范围内
  • 引用、耦合性----代码是否引用了一些不受代码自己直接控制的外部因素
  • 存在性----值是否存在(例如:非Null,非零,存在于某个集合中)
  • 基数性----是否刚好具备足够的值
  • 时间性----全部事情是否都按照顺序发生的?是否在正确的时间、是否及时

3.3 使用Mock对象

单元测试的目标是验证咱们的工做单元,可是若是这个工做单元依赖一些其余的对象或是一些难以操控的东西,好比网络、数据库等。这时咱们就要使用mock对象,使得在运行UT的时候使用的那些难以操控的东西其实是咱们mock的对象,而咱们mock的对象则能够按照咱们的意愿返回一些值用于测试。通俗来说,Mock对象就是真实对象在咱们调试期间的测试品。对于外部对象内的逻辑咱们并不关心,咱们只须要让它给咱们返回咱们想要的值,来验证咱们的业务逻辑便可

IFileExtensionManager fileManager;

public bool IsValidFileName(){
    //获取文件扩展名
    string extName=fileManager.GetExtName();
    if(extName=="jpg"){
        return true;
    }
    return false;
}

如上示例,假设从文件系统中读取一个文件,获取文件的扩展名,若是扩展名是jpg就返回true,不然返回false。
注意,这里咱们要测试的逻辑是若是扩展名是jpg就返回true,不然返回false。而对于fileManager.GetExtName()方法内部的逻辑是什么样的的咱们是不关心的,咱们只须要mock这个方法使其返回咱们想要的值就能够了。
关于具体如何去mock工做单元中的一些外部依赖,会在存根与模拟对象里面详细进行总结。

总结

本文总结了什么是单元测试、什么不是单元测试以及优秀的单元测试有哪些特性,简单介绍了如何进行单元测试。 编写差劲的单元测试是没有意义的,我看到过不少公司尝试去实践单元测试,但最终要么在某个阶段放弃了,要么并无真正执行单元测试。最终仍是依赖集成测试或者人工测试来发现问题,不得不以失败而了结,并冠冕堂皇的认为单元测试是一个耗时好力而无功的鸡肋东西。 所以若是你想要真正的去实践单元测试,那么必须充分的理解到底什么是单元测试,已经如何去更好的进行实践优秀的单元测试。 而对于如何更好的去实践单元测试,后续会结合实践用更多的篇幅去总结分享。

相关文章
相关标签/搜索