Spock单元测试框架实战指南十 您所在的位置:网站首页 spock测试框架 Spock单元测试框架实战指南十

Spock单元测试框架实战指南十

#Spock单元测试框架实战指南十| 来源: 网络整理| 查看: 265

Spock虽然好用,但要应用到实际项目中还是需要注意几个问题,下面讲下我们公司在使用过程中遇到的一些问题和解决方案

版本依赖

要使用Spock首先需要引入相关依赖,目前使用下来和我们项目兼容的Spock版本是1.3-groovy-2.5,以maven为例(gradle可以参考官网),完整的pom依赖如下:

1.3-groovy-2.5 2.5.4 org.spockframework spock-core ${spock.version} test org.spockframework spock-spring ${spock.version} test org.springframework spring-test test org.codehaus.groovy groovy-all pom ${groovy.version} groovy-test-junit5 org.codehaus.groovy groovy-testng org.codehaus.groovy org.codehaus.gmavenplus gmavenplus-plugin 1.6 compile compileTests

Spock是使用groovy语言写单测的,所以需要引入groovy-all的依赖

在引入 groovy-all 包时排除了 groovy-test-junit5 和 groovy-testng,这两个包和和 power mock 有冲突,在执行 mvn test 会导致NPE的问题

如果你的项目中没有用过groovy,还需要添加groovy的maven编译插件,这样才能编译我们用Spock写的单元测试

引入groovy依赖后可能会出现版本冲突的问题,因为如果你的项目引用了springboot-start-base这样的集合式jar包,它里面也会引用groovy,有可能跟我们引入的groovy包版本出现冲突,或者公司的一些框架也会引用groovy的包,如果版本不一致也有可能冲突,需要排下包

然后执行 mvn clean compile 验证下是否有冲突,如果能成功编译就没有这个问题

目前Spock的最新版本是2.0以上,在Spock 2.x 的版本里官方团队已经移除Sputnik,不再支持代理运行power mock的方式

因为Spock 2.0是基于JUnit5,我们项目以前的单元测试代码都是基于Junit4编写的,换成Junit5后,需要修改现有的java单测,比如指定代理运行,使用power mock的地方要换成Junit5的扩展语法

对现有使用Junit4 + power mock/jmockit的方式改变较大,为降低迁移成本没有使用最新的Spock2.X版本

如果你的项目之前就是使用Junit5写单测的,那么可以使用Spock2.X的版本,2.0以上版本使用power mock可以参考官方提供的解决方案:

(https://github.com/spockframework/spock/commit/fa8bd57cbb2decd70647a5b5bc095ba3fdc88ee9)

后续我也会优先在我的博客 www.javakk.com 推出 Spock2.x 版本的使用教程

创建单元测试文件

编译(mvn clean compile)通过之后,用spock编写的groovy类型的单测代码不能放在原来的test/java目录下面

因为按照groovy的约定,默认编译groovy包下的单测,所以需要建个groovy文件夹存放spock的单测代码,如下图所示:

这样也方便区分原来Java单测和用Spock写的单测代码

另外记得别忘了标记groovy目录为测试源目录(Test Source Root),如下图:

(groovy文件夹右键 → Mark Directory as → Test Sources Root)

第一次运行spock单测代码时如果提示"no test suite exist"的错误,可以右键recompile下

还有记得创建的单测文件类型是Groovy Class,不是Java Class类型

最后使用intellij idea的快捷键创建单元测试,在需要测试的类或方法上右键IDE的菜单,选择"Go To → Create New Test" 选择我们已经创建好的groovy文件夹:

这样就自动生成了groovy类型的单测文件了

运行单元测试

执行 mvn test,按照上面两步的配置保证spock单测代码运行成功后可以执行 mvn clean test 命令,跑一下这个项目的单测用例

(这一步不是必须的,但如果公司加了单测覆盖率的统计时,在cicd系统发布时或merge request to release代码合并到release分支时,会先执行mvn test类似的指令,确保所有的单元测试运行成功)

如果你的项目和我们一样既有Java单测又有Spock单测,需要确保两种单测都能执行成功(目前我们项目的spock单测和java单测在公司的CICD系统以及git上都能兼容和通过测试覆盖率要求)

另外按照Spock的规范,单测代码文件的命名应该是以Spec为后缀的,如果你严格按照这个规范命名单测文件,比如"OrderServiceSpec.groovy",那么需要在maven-surefire-plugin测试插件里添加以Spec为后缀的配置:

maven-surefire-plugin ${surefire.version} **/*Spec.java **/*Test.java

但是我是直接使用IDE生成单元测试,intellij idea自动生成的单测后缀还是“Test”,所以不存在这个问题,如果你也是这样,可以忽略这个问题

单元测试规范

Spock虽然使用方便,但还是要遵循单元测试的规范来,比如单元测试一般是针对方法或类的维度去测试的,也就是说我们关注的重点是当前类或方法内部的逻辑

如果当前被测方法依赖了其他层或module的逻辑,最好mock掉,尽量不要跨层测试,这属于功能测试或集成测试的范畴

比如使用@SpringBootTest注解,默认会把当前方法依赖的下一层引用也注入进来,其实完全可以交给Spock去控制,可以不需要SpringBootTest

Spock和Mockito注解混用问题

因为Spock并不支持Mockito和power mock的@InjectMocks和@Mock的组合,运行时会报错,如果你一定要使用对应的功能可以引入Mockitio为Spock专门开发的第三方工具:spock-subjects-collaborators-extension使用@Subject和@Collaborator代替@InjectMocks和@Mock

代码如下:

import spock.lang.Specification import com.blogspot.toomuchcoding.spock.subjcollabs.Collaborator import com.blogspot.toomuchcoding.spock.subjcollabs.Subject class ConstructorInjectionSpec extends Specification { public static final String TEST_METHOD_1 = "Test method 1" SomeOtherClass someOtherClassNotToBeInjected = Mock() @Collaborator // 类似于Mockito的@Mock SomeOtherClass someOtherClass = Mock() @Subject // 类似于Mockito的@InjectMocks SomeClass systemUnderTest def "should inject collaborator into subject"() { given: someOtherClass.someMethod() >> TEST_METHOD_1 when: String firstResult = systemUnderTest.someOtherClass.someMethod() then: firstResult == TEST_METHOD_1 systemUnderTest.someOtherClass == someOtherClass } class SomeClass { SomeOtherClass someOtherClass SomeClass(SomeOtherClass someOtherClass) { this.someOtherClass = someOtherClass } } class SomeOtherClass { String someMethod() { "Some other class" } } }

具体参考:

https://github.com/marcingrzejszczak/spock-subjects-collaborators-extension

我个人的建议是用PowerMockito.mock()的方式代替注解,虽没有注解的语法简洁,但不用再引入额外的依赖

Power Mock参数匹配方法 Any()

如果在Spock里使用了power mock的mock方法, 方法参数需要匹配的, 注意不要引用了spock的any()方法, 而应该使用power mock的any方法, 二者不能混用, 否则会报错

正确引用路径org.mockito.ArgumentMatchers:

错误引用路径org.codehaus.groovy.runtime.DefaultGroovyMethods:

记得前提是在powermock的api里使用参数匹配,如果是spock的mock方法,直接使用_下划线即可。

文章来源:http://javakk.com/322.html



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有