01.前言(一)

114 阅读11分钟

1.测试的本质

测试的本质是我们在生产代码写完之后在它上线之前我们要对这个代码的正确性进行验证的一个工作,单元测试就是整个自动化测试过程中最基本使用率最高覆盖率最多的一种测试的类型

2.为什么会出现自动化测试

基于测试的目的我们会发现我们即使不使用任何的工具,不使用任何的框架,即使不知道单元测试集成测试,我们也可以在代码上线之前对它进行验证,那需要大量的人工去操作,然后去对真实用户进行一个模拟然后把这个结果的期望进行一个验证,但是我们作为软件工程和开发者我们肯定不允许这种过多的人工参与的部分所以就会有自动化测试的出现,我们需要把这种测试的流程通过一些自动化的手段脚本或者是工具框架,来把它做成可以自动执行的可以很快反馈的一些测试类型

3.自动化测试的测试策略

如何去选择,下面这张图从成本和速度两个方面给我们做了一些指导,是更多覆盖面更广的单元测试,然后更少覆盖的链路更核心的集成测试和对UI的测试

4.测试的三大核心组成部分

  • 测试需要的参数
  • 测试的行为
  • 验证测试执行的结果

5.什么是单元测试

单元测试(Unit Test)是针对程序模块(软件设计的最小单位)来进行正确性校验的测试工作

单元测试这个概念是比较广泛的,咱们说的单元测试指的是在学习Junit的过程中,提到的狭义上的单元测试

单元测试(unit testing)是检验软件不同工作单元的行为测试。工作单元是不直接依赖于其他任何任务的任务。在Java应用程序中,工作单元通常是(但不总是)单个的方法。相比之下,集成测试和验收测试要检查多种组件如何交互

举个例子来说:“确保方法接收预期范围的输入值,并且该方法对每个输入值返回预期的值”。这个描述要求通过它的接口测试方法的行为。如果给它赋值x,它会返回y吗?如果给它赋值z,它会抛出正确的异常吗?

6.关于单元测试的误区

其他单元测试:软件测试乃至单元测试并不是JUnit团队的发明。单元测试这个术语最初用于描述检查单个工作单元(一个类或一个方法)行为的测试。随着时间的推移,这个术语的使用范围扩大了。例如,电气电子工程师学会(IEEE)将单元测试定义为“对单个硬件、软件单元或一组相关单元的测试”

狭义单元测试:狭义单元测试是针对一个类的一个公有、私有、保护方法的测试

广义单元测试:广义单元测试是针对一个类的一个公有方法的测试。首先,对于类的使用者来说,大多数情况下只能调用公有方法;其次,公有方法可能有私有、保护方法组成,独立存在的私有、保护方法是没有意义的;最后,在测试公有方法时,已经附带着测试私有、保护方法

在日常的单元测试中,大多使用广义单元测试,针对公有方法进行测试。当然,为了覆盖某些代码分支,也可以采用狭义单元测试,直接针对私有、保护方法进行测试

7.以案例看单元测试三大核心

以下是一个简单的单元测试的用例来看测试的三大核心

8.单元测试的特征

9.集成测试介绍

单元测试和集成测试使用的测试框架和工具大部分是相同的

首先需要达成一致的是,无论是单元测试还是集成测试,它们都是自动化测试。为了更好地区分,我们可以这样理解。和生产代码以及单元测试代码在同一个代码仓库中,由开发同学自己编写的,对外部环境(数据库、文件系统、外部系统、消息队列等)有真实调用的测试就是集成测试

10.单元测试和集成测试的区别

下表中也从各种角度来对比了单元测试、集成测试和系统级别测试的区别

11.为什么要写单元测试

对于团队的价值

核心价值:缩短反馈周期、降低缺陷修复成本

在开发过程后面,几乎每个流程都可能抛出Bug。越是到后面流程才抛出的Bug,程序员就越是要投入比开发阶段更大的时间和业务,而且所承受的风险也是最高的

下面这张图,也在说明两个问题:一是85%的缺陷都在代码设计阶段产生;二是发现Bug的阶段越靠后,耗费成本就越高,呈指数级别的增长。这种 “指数成本” 的案例也经常发生,当我们改正一个Bug的时候,可能随之而来又会多出3个Bug,俗称:改崩了

所以,在早期的单元测试就能发现bug,不仅可以省时省力,在开发流程上提高效率,也能降低反复修改出现的风险和时间成本

对于个人的价值

总结

12.单元测试适用场景

  • 代码复用率:代码复用率越高,越有必要推行单测,越有必要提升单测的要求。因此这些代码被很多业务引用,因此其一旦有问题便会影响很多业务方,在这样的代码推行单测是收益较高的
  • 业务变化率:业务变化越快,越不适合用单测。如果业务变化非常快,一个单测的内容上线了没几天就又要修改,那么你不仅仅需要修改业务代码,还需要修改单测代码,那就是双倍的工作量了
  • 人员变化率:人员变化率指的是某个模块负责人的变化情况。如果某个模块的负责人经常变来变去,那么也是不太适合推行单测的。因为新负责的人需要花大量的时间去熟悉单测的内容,这会导致需求开发的时间变得非常长
  • 业务重要性:越是核心的业务,越有必要推行单测,并且越有必要以高标准要求。因为核心业务的稳定性、健壮性对于公司来说肯定非常重要,而单测确实是能够在最小单元去提升系统稳定性和系统健壮性

13.好的单元测试必须遵守的原则

其他注意点

  • 配合断言使用(杜绝System.out)
  • Spring的上下文环境不是必须的
  • 一般都需要配合mock类框架来实现
  • 不会对数据产生影响

AIR原则

介绍

单元测试在线上运行时,感觉像空气(AIR)一样感觉不到,但在测试质量的保障上,却是非常关键的。好的单元测试宏观上来说,具有自动化、独立性、可重复执行的特点

详解

  • A:Automatic(自动化)单元测试应该是全自动执行的,并且非交互式的。测试用例通常是被定期执行的,执行过程必须完全自动化才有意义。输出结果需要人工检查的测试不是一个好的单元测试
  • I:Independent(独立性)保持单元测试的独立性。为了保证单元测试稳定可靠且便于维护,单元测试用例之间决不能互相调用,也不能依赖执行的先后次序。反例:method2需要依赖method1的执行,将执行结果做为method2的参数输入
  • R:Repeatable(可重复)单元测试是可以重复执行的,不能受到外界环境的影响。说明:单元测试通常会被放到持续集成中,每次有代码check in时单元测试都会被执行。如果单测对外部环境(网络、服务、中间件等)有依赖,容易导致持续集成机制的不可用。正例:为了不受外界环境影响,要求设计代码时就把SUT的依赖改成注入,在测试时用spring 这样的DI框架注入一个本地(内存)实现或者Mock实现

FIRST原则

  • F-Fast(快速的):单元测试应该是可以快速运行的,在各种测试方法中,单元测试的运行速度是最快的,大型项目的单元测试通常应该在几分钟内运行完毕
  • I-Independent(独立的):单元测试应该是可以独立运行的,单元测试用例互相之间无依赖,且对外部资源也无任何依赖
  • R-Repeatable(可重复的):单元测试应该可以稳定重复的运行,并且每次运行的结果都是稳定可靠的
  • S-SelfValidating(自我验证的):单元测试应该是用例自动进行验证的,不能依赖人工验证
  • T-Timely(及时的):单元测试必须及时进行编写,更新和维护,以保证用例可以随着业务代码的变化动态的保障质量

BCDE原则

介绍

编写单元测试代码遵守BCDE原则,以保证被测试模块的交付质量

详解

  • B:Border,边界值测试,包括循环边界、特殊取值、特殊时间点、数据顺序等
  • C:Correct,正确的输入,并得到预期的结果
  • D:Design,与设计文档相结合,来编写单元测试
  • E:Error,强制错误信息输入(如:非法数据、异常流程、非业务允许输入等),并得到预期的结果

14.Mock测试

介绍

什么是Mock测试Mock的中文译为仿制的,模拟的,虚假的。对于测试框架来说,即构造出一个模拟/虚假的对象,使我们的测试能顺利进行下去

Mock测试就是在测试过程中,对于某些不容易构造(如HttpServletRequest必须在Servlet容器中才能构造出来)或者不容易获取比较复杂的对象(如JDBC中的ResultSet对象),用一个 虚拟 的对象(Mock对象)来创建,以便测试方法

为什么使用Mock测试

介绍

单元测试是为了验证我们的代码运行正确性,我们注重的是代码的流程以及结果的正确与否

对比真实运行代码,可能其中有一些 外部依赖的构建步骤相对麻烦,如果我们还是按照真实代码的构建规则构造出外部依赖,会大大增加单元测试的工作,代码也会参杂太多非测试部分的内容,测试用例显得复杂难懂

采用Mock框架,我们可以虚拟出一个外部依赖,只注重代码的流程与结果,真正地实现测试目的

例子

像是以下这张图,类A需要调用类B和类C,而类B和类C又需要调用其他类如D、E、F等,假设类D是一个外部服务,那就会很难测,因为你的返回结果会直接的受外部服务影响,导致你的单元测试可能今天会过、但明天就过不了了

而当我们引入Mock测试时,就可以创建一个假的对象,替换掉真实的Bean B 和C,这样在调用B、C的方法时,实际上就会去调用这个假的Mock对象的方法,而我们就可以自己设定这个Mock对象的参数和期望结果,让我们可以专注在测试当前的类A,而不会受到其他的外部服务影响,这样测试效率就能提高很多

Mock测试框架的好处

  • 可以很简单的虚拟出一个复杂对象(比如虚拟出一个接口的实现类)
  • 可以配置mock对象的行为
  • 可以使测试用例只注重测试流程与结果
  • 减少外部类、系统和依赖给单元测试带来的耦合

常用的mock框架

  • mockito
  • easymock
  • powermock
  • JMockit