Spock尽管好用,但要利用到理论我的项目中还是须要留神几个问题,上面讲下咱们公司在应用过程中遇到的一些问题和解决方案
版本依赖
要应用Spock首先须要引入相干依赖,目前应用下来和咱们我的项目兼容的Spock版本是1.3-groovy-2.5
,以maven为例(gradle能够参考官网),残缺的pom依赖如下:
<spock.version>1.3-groovy-2.5</spock.version><groovy.version>2.5.4</groovy.version> <!-- spock --><dependency> <groupId>org.spockframework</groupId> <artifactId>spock-core</artifactId> <version>${spock.version}</version> <scope>test</scope></dependency><!-- spock和spring集成 --><dependency> <groupId>org.spockframework</groupId> <artifactId>spock-spring</artifactId> <version>${spock.version}</version> <scope>test</scope></dependency><dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <scope>test</scope></dependency><!-- spock依赖的groovy --><dependency> <groupId>org.codehaus.groovy</groupId> <artifactId>groovy-all</artifactId> <type>pom</type> <version>${groovy.version}</version> <exclusions> <exclusion> <artifactId>groovy-test-junit5</artifactId> <groupId>org.codehaus.groovy</groupId> </exclusion> <exclusion> <artifactId>groovy-testng</artifactId> <groupId>org.codehaus.groovy</groupId> </exclusion> </exclusions></dependency> <!--groovy 编译--><plugin> <groupId>org.codehaus.gmavenplus</groupId> <artifactId>gmavenplus-plugin</artifactId> <version>1.6</version> <executions> <execution> <goals> <goal>compile</goal> <goal>compileTests</goal> </goals> </execution> </executions></plugin>
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为后缀的配置:
<plugin> <artifactId>maven-surefire-plugin</artifactId> <version>${surefire.version}</version> <configuration> <includes> <include>**/*Spec.java</include> <include>**/*Test.java</include> </includes> </configuration></plugin>
然而我是间接应用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.Specificationimport com.blogspot.toomuchcoding.spock.subjcollabs.Collaboratorimport 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