spock框架进行单元测试的学习与实践
单元测试
一个稳定的系统少不了单元测试,单元测试(又称为模块测试, Unit Testing)是针对程序模块(软件设计的最小单位)来进行正确性检验的测试工作。
对于面向对象编程,最小单元就是方法,包括父类、抽象类、或者子类中的方法。
所以单元测试的特点:
- 测试的是一个代码单元内部的逻辑,而不是各模块之间的交互。
- 无依赖,不需要实际运行环境就可以测试代码。
- 运行效率高,可以随时执行。
而单元测试的应用场景一般主要有这几个:
- 测试驱动开发,由于工期限制,几乎无法实现
- 对每次代码修改做回归测试
spock测试框架
简介
Spock是基于JUnit的单测框架,提供一些更好的语法,结合Groovy语言,可以写出更为简洁的单测,它的语法完全遵循 BDD(行为驱动开发) 风格的结构。同时集成了像 Jmock、Mockito 等语法表达风格于一体,使得它很简洁有很高的可读性
与其他单元测试框架对比
Spock相比JUnit有易读、简洁、自带Mock等特性,可以减少单元测试编写时间,而且bug更少,可读性更好,写出的单元测试代码更优雅,更易于阅读!
Spock提供了覆盖Java企业应用的完整的测试生命周期。其他框架,是基于某种需要产生的,比如:Junit单纯用于单测,但不提供mock;Mockito提供mock功能,但不提供静态类的mock;PowerMock提供静态类mock;
它们之间需要整合,且不容易跟上新的测试场景。Spock提供了全家桶测试,内置了mock和stub功能等,很方便上手
特点
- 全能,高效,代码简介,易读,方法名支持中文
- 提供Groovy的closures,类似Java8的lambda表达式
- Mockito对参数匹配有限制。如果在方法中使用匹配器,那么所有的参数都需要匹配器。Spock不受此限制,可以将实参与实参匹配器混合和匹配
- Spock区分了Stub和Mock,让单测更易读
- Spock提供了更多详细的错误信息
基础
关于依赖
依赖如果版本对不上会报各种各样的错,所以最好是根据maven仓库中查看版本,一定要对应上:
比如如果是3.0版本的spock-core,groovy依赖就必须是:
基本用法
需要创建groovy类使用spock,所有的类都要继承Specification类,如下:
class SpockDemoSpec extends Specification{
/**
* 在第一个测试方法开始前执行一遍
*/
def setupSpec() { println "------------ setupSpec: 所有测试开始之前执行 ------------" }
/**
* 每个测试方法开始前都会执行一遍
*/
def setup() { println "------------ setup:每个测试方法开始之前执行 ------------" }
/**
* 每个测试方法后都会执行一遍
*/
def cleanup() { println "------------ cleanup:每个测试方法结束之后执行 ------------" }
/**
* 最后一个测试方法后执行
*/
def cleanupSpec() { println "------------ cleanupSpec: 所有测试方法结束之后执行 ------------" }
def "测试given-expect"() {
given:
def a = new Random().nextInt(10)
def b = 2
expect:
println a
a > b
}
def "测试where"() {
expect:
result == ++id
// where表格 左边是参数,右边是测试结果
where:
id | result
10 | 11
100 | 101
1000 | 1001
}
def "测试given-when-then"() {
given:
// 数据准备
def a = "houzheng"
when:
// 条件判断
boolean flag = a.equals("houzheng")
then:
// 期望结果
flag
}
def "测试异常thrown"() {
when:
// 此方法会抛出RuntimeException
throw new RuntimeException("模拟异常");
then:
// 接收异常
def ex = thrown(Exception)
ex.class.name == "java.lang.RuntimeException"
ex.getMessage() == "模拟异常"
}
}
Demo执行结果:
- where: 以表格的形式提供测试数据集合
- when: 触发行为,比如调用指定方法或函数
- then: 做出断言表达式
- expect: 期望的行为,when-then的精简版
- given: mock单测中指定mock数据
- thrown: 如果在when方法中抛出了异常,则在这个子句中会捕获到异常并返回
- def setup() {} :每个测试运行前的启动方法
- def cleanup() {} : 每个测试运行后的清理方法
- def setupSpec() {} : 第一个测试运行前的启动方法
- def cleanupSpec() {} : 最后一个测试运行后的清理方法
springboot中的使用
常用注解
项目中实际使用
笔者目前项目中某个业务的使用
与原来单元测试代码的对比
打包运行
测试报告输出
心得体会与总结
- 兼容性比较差,依赖版本稍微不对,就会报一些莫名其妙的错误,而且提示也不明显,不太好排查
- 其实虽然说要懂groovy,但是懂java的人还是非常容易上手的,只要给一个demo,基本就能够写单测了
- 如果还想写的更优雅更高级,那可以去学学groovy,这里放一下笔者的链接:https://www.cnblogs.com/houzheng/p/15183586.html , 有兴趣可以看看