乐趣区

关于java:Spock单元测试框架实战指南十-注意事项

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

正确援用门路org.mockito.ArgumentMatchers

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

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

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

退出移动版