在上一篇中,我们介绍了什么是Spock以及它和JUnit,JMock等其它测试框架的对比,从这一篇开始,我们将开始详细介绍Spock的使用。
在这一章,我们首先讲解如何在项目中引入Spock,以及Spock的一些核心概念介绍,并且抛砖引玉给出一个简单的单测示例。
引入Spock- 环境
针对Java单元测试,开发工具 IntelliJ IDEA。
- Maven依赖
<!--
可以只引入这一个包,它已经引入了 spock-core、groovy-all; 如果有冲突可以手动指定版本引入
此包是整合springboot使用,用于在spock中启动springboot容器,
如果仅想使用spock作为单测使用,可以不引入当前包,只引入 spock-core、groovy-all 即可
-->
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-spring</artifactId>
<version>1.3-groovy-2.4</version>
</dependency>
<!-- 可以不引入 -->
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-core</artifactId>
<version>1.3-groovy-2.4</version>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy</artifactId>
<version>2.4.17</version>
</dependency>
- 插件配置
在单测用例所在module的 pom文件添加plugin的配置,多module的情况下放主pom不生效
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.22.2</version> <configuration> <skipTests>false</skipTests> <parallel>classes</parallel> <threadCount>4</threadCount> <forkCount>1C</forkCount> <includes> <include>**/*Test.java</include> <include>**/*Spec.java</include> </includes> </configuration> </plugin> <plugin> <!--groovy plugin--> <groupId>org.codehaus.gmavenplus</groupId> <artifactId>gmavenplus-plugin</artifactId> <version>1.4</version> <extensions>true</extensions> <executions> <execution> <goals> <goal>compile</goal> <goal>testCompile</goal> </goals> </execution> </executions> <configuration> <!-- spock单测文件路径 --> <testSources> <testSource> <directory>${project.basedir}/src/test/java</directory> <includes> <include>**/*.groovy</include> </includes> </testSource> <testSource> <directory>${project.basedir}/src/test/groovy</directory> <includes> <include>**/*.groovy</include> </includes> </testSource> </testSources> </configuration> </plugin>
- 引入过程中的注意点
问题1:java.lang.NoClassDefFoundError: org/codehaus/groovy/transform/stc/AbstractExtensionMethodCache
解决:将groovy 和 groovy-all 都保持2.4.17版本
问题2:配置了gmavenplus-plugin并指定了路径但不生效
配置在主pom中,但单测在B模块中导致,将插件配置到A或B模块中
主pom
|----A
|----B
问题3:引入groovy依赖后可能会出现版本冲突的问题
因为如果你的项目引用了springboot-start-base这样的集合式jar包,它里面也会引用groovy,有可能跟我们引入的groovy包版本出现冲突,或者公司的一些框架也会引用groovy的包,如果版本不一致也有可能冲突,需要排下包。
这里推荐idea的maven插件 MavenHelper 能可视化快速排查依赖问题。
MavenHelper依赖分析
Spock核心概念
- Spock标签
标签
作用
备注
given
为所测试方法做一些前置准备工作的地方
一般将方法内部依赖的参数在这个标签内完成
when
执行测试
when 和 then 必须成对出现
then
验证测试结果是否符合预期
when 和 then 必须成对出现
expect
精简版when then
expect里代码只可以包含布尔表达式
and
承接上一个标签
where
用于编写数据驱动的用例方法
总是在方法的最后,且不能重复
cleanup
测试方法退出前执行一些清理工作
一个 cleanup 后仅仅只能跟一个where ,即使前面发生了异常cleanup也会运行(类似于Java的finally)
- Mock、Stub和Spy区别
Spock单测示例
方法
描述
Mock()
Mock的对象是一个虚拟类,为每个方法调用返回了一个默认值,用于替换真实的类。Mock()不仅可以模拟方法返回结果,还可以模拟方法行为,比如验证某个方法是否被调用以及调用次数
Stub()
Stub的对象也是一个虚拟类,比Mock()更简单些。只返回事先准备好的测试数据,而不提供交互验证
Spy()
又叫刺探方法,它会包装一个真实的对象,默认情况下将调用真实的方法。Spy()功能最强大,但这样做意味着代码可能有坏味道,设计上可能有问题。
待测试类:
public class square { private final int length; public Square(int length) { this.length = length; } public int area() { return length * length; } public int perimeter() { return length * 4; } }
测试类:
class SquareTest extends Specification { @Unroll def "given square length: #length, square area: #area, square perimeter: #perimeter"() { given: def square = new Square( length: length ) expect: square.area() == area square.perimeter() == perimeter where: length || area | perimeter 1 || 1 | 4 2 || 4 | 8 } }
def 是groovy的关键字,可以用来定义变量和方法名,这里可以用英文也可以用中文。
expect...where... expect为核心的测试校验语句块,where则是多个测试用例的举例,多个列使用"|"单竖线隔开,"||"双竖线区分输入和输出变量,即左边是输入值,右边是输出值。表格列的长度不一样,手动对齐比较麻烦,intellij idea支持format格式化快捷键。
上面图中定义的测试方法名使用了groovy的字面值特性,即把请求参数值和返回结果值的字符串动态替换掉,"#length、#area、#perimeter" #号后面的变量是在方法内部定义的,前面加上#号,实现占位符的功能。
@Unroll 注解,可以把每一次调用作为一个单独的测试用例运行,这样运行后的单测结果更直观:
如果其中一行测试结果错误,spock的错误提示信息也很详细,方便我们排查(比如我们把第2行测试用例返回的perimeter改成4)
总结
在这篇文章中,我们引入了Spock,并对Spock的一些概念做了简单介绍,最后给出一个简单的测试示例,进一步加深对Spock的理解。下一篇章我们将会详细的介绍如何通过Spock测试复杂的if-else场景。
,