单元测试实践三板斧—开篇

一、什么是单元测试

单元测试是指对软件中的最小可测试单元进行检查和验证。单元在质量保证中是非常重要的环节,根据测试金字塔原理,越往上层的测试,所需的测试投入比例越大,效果也越差,而单元测试的成本要小的多,也更容易发现问题。
然而然而我们大多数人是不会写单元测试的,甚至不知道单元测试究竟是为了干什么。单元测试几个典型场景如下:

  1. 开发前写单元测试,通过测试描述需求,由测试驱动开发。
  2. 在开发过程中及时得到反馈,提前发现问题。
  3. 应用于自动化构建或持续集成流程,对每次代码修改做回归测试(我们要继承Bamboo)。
  4. 作为重构的基础,验证重构是否可靠。

二、单元测试核心原则

优秀的单元测试可以很好的在早起捕捉到导致系统奔溃的问题,而编写一个优秀的单元测试要遵循一定的原则,测试相关原则有很多,这里总结了我个人认为比较重要的几条原则:

  • 自动化原则:单元测试应该是全自动执行的,利用断言Assert进行结果验证,自动给出结果。
  • 独立原则:保持单元测试的独立性。单元测试用例之间互不依赖,对外部资源(网络、服务、中间件等)无依赖,也不能依赖执行的先后次序。
  • 可重复原则:单元测试是可以重复执行的,每次运行的结果应该是相同的。如果单测对外部环境(网络、服务、中间件等)有依赖,容易导致持续集成机制的不可用。
  • 快速原则:单元测试应该是可以快速运行的,在各种测试方法中,单元测试的运行速度是最快的,保证开发人员可以对每一个小变更快速测试,不应该启动加载整个环境。
  • 全面性原则:除了正确的输入得到预期的结果,还需要强制错误信息输入得到预期的结果,为了系统的鲁棒性,应加入边界值测试,包括循环边界、特殊取值、特殊时间点、数据顺序等。
  • 专注性原则:保证测试小而专注,有助于精确定位问题。单测粒度一般是方法级别,测试某个具体行为。单测不负责检查跨类或者跨系统的交互逻辑,那是集成测试的领域。

三、单元测试痛点

对于单元测试而言,我们在编写的过程中通常会遇到如下几类问题:

  1. 介绍单元测试相关的资料比较少,大部分资料介绍单元测试仅仅介绍了一个JUnit测试函数类怎么写,Assert断言怎么写就结束了,实际应用到复杂的系统工程里应该怎么做很少涉及。
  2. 微服务架构下,系统依赖各种外部接口和中间件,要写一个纯粹的无依赖的单元测试是很困难的。大部分java开发同学写单元测试,都是基于Junit框架启动整个Spring上下文环境来编写单元测试,因此完美的绕开了上面提到的几个单测原则。
  3. 单元测试难以理解和维护,无论什么单元测试框架,如果要维持较高的单元测试覆盖率,均要有约三倍于业务代码,再有单测代码本身不像业务代码直观,还有对单测代码可读性不够重视的习惯,导致单测难以阅读和维护。

基于以上几个痛点,经过多方考量权衡,我在项目中使用spock框架作为单测主要框架进行了单元测试的编写,后续单测介绍大部分为Spock写法。将单元测试实践分为以下3篇:
First Blood —— 业务逻辑层测试实践
Double Kill —— Controller层测试实践
Triple Kill —— 数据层测试实践

四、前期知识储备

4.1 Groovy语言基础

Spock是基于Groovy脚本语言的测试框架,所以再正式开始之前,我们有必要先简单了解一下语法基础,使用非常简单,开发人员几分钟上手不是问题。详细教程可参考:https://www.w3cschool.cn/groovy

Groovy和Java的语法对比

  1. 不需public修饰符,Groovy的默认访问修饰符就是public,如果Groovy类成员需要public修饰,则根本不用写它
  2. 不需要构造函数,不再需要程序员声明任何构造函数,因为实际上只需要两个构造函数(1个不带参数的默认构造函数,1个只带一个map参数的构造函数–由于是map类型,通过这个参数可以构造对象时任意初始化它的成员变量)
  3. 数组(列表)用中括号表示,[v1, v2, v3]
  4. 字典映射使用冒号分隔键值对,[k1: v1, k2: v2, k3: v3],初始化一个空的Map,写法为[:]
  5. 支持类型自动推断,使用关键字 def,比如 def var = “value”; 也可以使用java的方式显示定义String var = “value”
  6. for-in循环示例,int[] array = [0,1,2,3], for(int i in array) { println(i) }
  7. 支持范围类型,比如 1…3 相当于 Java 中的数组 { 1, 2, 3 };1.2…3 相当于 Java 中的数组 { 1.2, 2.2 };1…❤️ 相当于数组 { 1, 2 };‘a’…‘z’ 相当于所有小写字母的字符集合。范围类型是可迭代的。
  8. Groovy 中的除法默认是小数除法,不是整数除法。

4.2 单测插件配置

<!-- 生成单元测试数据插件 -->
<plugins>
  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.22.2</version>
   </plugin>
</plugins>

<!-- 生成JaCoCo覆盖率数据插件 -->
<plugin>
    <groupId>org.jacoco</groupId>
    <artifactId>jacoco-maven-plugin</artifactId>
    <version>0.8.2</version>
    <executions>
     <execution>
      <goals>
       <goal>prepare-agent</goal>
      </goals>
     </execution>
     <!-- attached to Maven test phase -->
     <execution>
      <id>report</id>
      <phase>test</phase>
      <goals>
       <goal>report</goal>
      </goals>
     </execution>
    </executions>
</plugin>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值