Spock单元测试框架系列(二):Spock使用详解

Spock单元测试框架系列(二):Spock使用详解

精选文章moguli202025-05-24 18:36:122A+A-

上一篇中,我们介绍了什么是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 能可视化快速排查依赖问题。

Spock核心概念

  • Spock标签

标签

作用

备注

given

为所测试方法做一些前置准备工作的地方

一般将方法内部依赖的参数在这个标签内完成

when

执行测试

when 和 then 必须成对出现

then

验证测试结果是否符合预期

when 和 then 必须成对出现

expect

精简版when+then

expect里代码只可以包含布尔表达式

and

承接上一个标签


where

用于编写数据驱动的用例方法

总是在方法的最后,且不能重复

cleanup

测试方法退出前执行一些清理工作

一个 cleanup 后仅仅只能跟一个where ,即使前面发生了异常cleanup也会运行(类似于Java的finally)

  • Mock、Stub和Spy区别

方法

描述

Mock()

Mock的对象是一个虚拟类,为每个方法调用返回了一个默认值,用于替换真实的类。Mock()不仅可以模拟方法返回结果,还可以模拟方法行为,比如验证某个方法是否被调用以及调用次数

Stub()

Stub的对象也是一个虚拟类,比Mock()更简单些。只返回事先准备好的测试数据,而不提供交互验证

Spy()

又叫刺探方法,它会包装一个真实的对象,默认情况下将调用真实的方法。Spy()功能最强大,但这样做意味着代码可能有坏味道,设计上可能有问题。

Spock单测示例

待测试类:

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场景。

点击这里复制本文地址 以上内容由莫古技术网整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!
qrcode

莫古技术网 © All Rights Reserved.  滇ICP备2024046894号-2