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-junit5groovy-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 mockmock办法, 办法参数须要匹配的, 留神不要援用了spock的any()办法, 而应该应用power mock的any办法, 二者不能混用, 否则会报错

正确援用门路org.mockito.ArgumentMatchers

谬误援用门路org.codehaus.groovy.runtime.DefaultGroovyMethods

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

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