一、导入依赖

Spock是基于JUnit的单测框架,提供一些更好的语法,结合Groovy语言,可以写出更为简洁的单测。

<!-- groovy依赖 -->
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>2.4.0</version>
</dependency>
<!-- spock核心依赖 -->
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-core</artifactId>
<version>1.3-groovy-2.4</version>
<scope>test</scope>
</dependency>
<!-- spring spock依赖 -->
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-spring</artifactId>
<version>1.3-groovy-2.4</version>
<scope>test</scope>
</dependency>
<!-- 单元测试依赖 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>

二、测试例子

继承Specification

package com.qiang.groovy.controller

import com.qiang.groovy.controller.ConfigInfoController
import spock.lang.Specification class ConfigInfoControllerGroovy extends Specification { }

固定方法

/**
* 在第一个测试方法开始前执行一遍
*/
def setupSpec() {
println "------------ setupSpec()方法 ------------"
} /**
* 每个测试方法开始前都会执行一遍
*/
def setup() {
println "------------ setup()方法 ------------"
} /**
* 每个测试方法后都会执行一遍
*/
def cleanup() {
println "------------ cleanup()方法 ------------"
} /**
* 最后一个测试方法后执行
*/
def cleanupSpec() {
println "------------ cleanupSpec()方法 ------------"
}

测试例子

def "测试a>b"() {
given:
def a = new Random().nextInt(10)
def b = 2
expect:
println a
a > b
}

点击运行

测试通过

测试不通过

三、基本构造

  • where: 以表格的形式提供测试数据集合
  • when: 触发行为,比如调用指定方法或函数
  • then: 做出断言表达式
  • expect: 期望的行为,when-then的精简版
  • given: mock单测中指定mock数据
  • thrown: 如果在when方法中抛出了异常,则在这个子句中会捕获到异常并返回
  • def setup() {} :每个测试运行前的启动方法
  • def cleanup() {} : 每个测试运行后的清理方法
  • def setupSpec() {} : 第一个测试运行前的启动方法
  • def cleanupSpec() {} : 最后一个测试运行后的清理方法

四、构造例子

4.1 expect-where

在where子句中以表格形式给出一系列输入输出的值,然后在expect中引用。

@Unroll
def "测试expect-where"() {
expect:
userInfoService.getById(id).getName() == name
where:
id | name
1 | "小强"
2 | "傻狗"
3 | "小猪"
}

4.2 given-when-then

当条件满足时,达到期望的结果。

@Unroll
@Transactional
def "测试given-when-then"() {
given:
// 数据准备
UserInfo userInfo = new UserInfo()
userInfo.setName("小强崽")
userInfo.setAsset(10000000.00)
when:
// 条件判断
boolean flag = userInfoService.save(userInfo)
then:
// 期望结果
flag
}

4.3 when-then-thrown

测试异常信息。

/**
* 模拟异常
*/
@Override
public void getExceptionMessage() {
throw new RuntimeException("模拟异常");
}

测试方法。

def "测试异常thrown"() {
when:
// 此方法会抛出RuntimeException
userInfoService.getExceptionMessage()
then:
// 接收异常
def ex = thrown(Exception)
ex.class.name == "java.lang.RuntimeException"
ex.getMessage() == "模拟异常"
}

五、远程挡板

远程调用第三方服务需要Mock挡板,避免受第三方服务的影响。

远程调用服务

package com.qiang.groovy.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.qiang.common.response.ResponseResult;
import com.qiang.groovy.entity.UserInfo;
import com.qiang.groovy.feign.GiteeServiceFeign;
import com.qiang.groovy.service.UserInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*; import java.io.Serializable;
import java.util.List; /**
* @author 小强崽
* @create: 2021-04-11 21:31:14
* @description: 控制层
*/
@RestController
@RequestMapping("/user/info")
public class UserInfoController {
/**
* 注入远程调用接口
*/
@Autowired
private GiteeServiceFeign giteeServiceFeign; /**
* 远程调用
*
* @param msg
* @return
*/
@GetMapping("/gitee/test/feign")
public ResponseResult<String> testFeign(@RequestParam("msg") String msg) {
return giteeServiceFeign.testFeign(msg);
}
}

远程调用做挡板后,自定义挡板返回的参数即可。

package com.qiang.groovy.controller

import com.qiang.common.response.ResponseResult
import com.qiang.common.util.SpringContextUtil
import com.qiang.groovy.feign.GiteeServiceFeign
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import spock.lang.Specification @SpringBootTest
class UserInfoControllerGroovy extends Specification { @Autowired
private UserInfoController userInfoController @Autowired
private SpringContextUtil springContextUtil; /**
* 单元测试调用第三方服务时,需要做挡板
*/
def giteeServiceFeign = Mock(GiteeServiceFeign) def "测试远程调用"() {
given:
// 定义挡板返回的参数,(*_)为任意入参参数
giteeServiceFeign.testFeign(*_) >> ResponseResult.success()
expect:
userInfoController.testFeign(msg).code == result
where:
msg | result
"msg" | "200"
} /**
* 每个测试方法开始前都会执行一遍
*/
def setup() {
// 挡板赋值
userInfoController.giteeServiceFeign = giteeServiceFeign
} /**
* 每个测试方法后都会执行一遍
*/
def cleanup() {
// 还原挡板
userInfoController.giteeServiceFeign = springContextUtil.getBean(GiteeServiceFeign.class)
} }

六、常用注解

6.1 @Unroll

某个测试用例失败了,却难以查到是哪个失败了,这时候,可以使用@Unroll注解,该注解会将where子句的每个测试用例转化为一个 @Test 独立测试方法来执行,这样就很容易找到错误的用例。

@Unroll
def "测试getById()"() {
expect:
userInfoService.getById(id).getName() == name
where:
id | name
1 | "小强"
2 | "傻狗"
3 | "小猪"
}

没加@Unroll之前

加了@Unroll之后

6.2 @Transactional

插入数据时,加上该注解测试完成会回滚数据。

作者(Author):小强崽

来源(Source):https://www.wuduoqiang.com/archives/Groovy+Spock单元测试

协议(License):署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)

版权(Copyright):商业转载请联系作者获得授权,非商业转载请注明出处。 For commercial use, please contact the author for authorization. For non-commercial use, please indicate the source.

Groovy+Spock单元测试的更多相关文章

  1. 使用Groovy+Spock构建可配置的订单搜索接口测试用例集

    概述 测试是软件成功上线的安全网.基本的测试包含单元测试.接口测试.在 "使用Groovy+Spock轻松写出更简洁的单测" 一文中已经讨论了使用GroovySpock编写简洁的单 ...

  2. Groovy/Spock 测试导论

    Groovy/Spock 测试导论 原文 http://java.dzone.com/articles/intro-so-groovyspock-testing 翻译 hxfirefox 测试对于软件 ...

  3. 使用Groovy+Spock轻松写出更简洁的单测

    当无法避免做一件事时,那就让它变得更简单. 概述 单测是规范的软件开发流程中的必不可少的环节之一.再伟大的程序员也难以避免自己不犯错,不写出有BUG的程序.单测就是用来检测BUG的.Java阵营中,J ...

  4. Compile Groovy/Spock with GMavenPlus

    在之前的博文里曾使用GMaven插件编译Groovy/Spock,这次使用GMavenplus插件,更加方便. 具体步骤 1. 导入Spock和Groovy依赖 <dependency> ...

  5. SpringCloud升级之路2020.0.x版-40. spock 单元测试封装的 WebClient(下)

    本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 我们继续上一节,继续使用 spock 测试我们自己封装的 WebClient 测试针对 r ...

  6. 人生苦短?试试Groovy进行单元测试

    如果您今天正在编程,那么您很可能听说过单元测试或测试驱动的开发过程.我还没有遇到一个既没有听说过又没有听说过单元测试并不重要的程序员.在随意的讨论中,大多数程序员似乎认为单元测试非常重要. 但是,当我 ...

  7. SpringCloud升级之路2020.0.x版-40. spock 单元测试封装的 WebClient(上)

    本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 我们来测试下前面封装好的 WebClient,这里开始,我们使用 spock 编写 gro ...

  8. Groovy Spock环境的安装

    听说spock是一个加强版的Junit,今天特地安装了,再把过程给大家分享一下. 首先说明,我的Java项目是用maven管理的. 我用的Eclipse是Kelper,开普勒. 要使用Spock之前, ...

  9. [每日一学]apache camel|BDD方式开发apache camel|Groovy|Spock

    开发apache camel应用,最好的方式就是tdd,因为camel的每个组件都是相互独立并可测试的. 现在有很多好的测试框架,用groovy的Spock框架的BDD(行为测试驱动)是比较优秀和好用 ...

随机推荐

  1. POJ3264线段树求最值

    刚开始还觉得有点怪怪的.因为想着如果每个树只是单纯地记录它所在的区间的话会不会有不在区间内的数据给更新了,但是我好像是傻掉了因为如果有这种情况出现的话在父亲节点就会分成l,mid和mid+1,r两个区 ...

  2. SSM和Maven整合

    项目架构如图 applicationContext.xml还有其他文件一起放进resources下 jsp,js,等文件放在webapp下

  3. odoo源生打印【web report】

    https://www.odoo.com/documentation/12.0/reference/reports.html     具体的看官方文档 一.纸张格式设置: <record id= ...

  4. Win10强制程序高DPI缩放设置

    起因 工作原因,需要在win10上安装数个古老vc版本(vc6,vc2008,vc2010),但是显示器是2K的,DPI缩放有问题 尝试 VC6比较好解决:右键,属性,兼容性,更改高DPI设置,勾选替 ...

  5. Vue 2升级 Vue 3初探小细节

    前言 嗯,偶尔看看学习Vue 3技能啦,此前用过Vue 2做过一点东西,Vue 3已面世一段时间,于是乎,我来看看所遇到的问题是否在Vue 3中得到解决,首先,我们来讲讲一个例子在Vue 2中的实现, ...

  6. 说说Java异步调用的几种方式

    日常开发中,会经常遇到说,前台调服务,然后触发一个比较耗时的异步服务,且不用等异步任务的处理结果就对原服务进行返回.这里就涉及的Java异步调用的一个知识.下面本文尝试将Java异步调用的多种方式进行 ...

  7. vue实现单点登录的N种方式

    最近项目停工了,RageFrame的学习暂时告一段落,这一篇给大家分享下有关单点登录的相关知识,并提供一些demo给大家参考,希望对想了解的朋友有一些帮助. 话不多说,先上原理(借鉴地址:https: ...

  8. 记录21.07.23 —— Vue.js基础(二)

    Vue基础(二) 过滤器 过滤器作用 全局过滤器 输出结果 私有过滤器 输出结果 把其中一个做点修改 错误信息 自定义指令 全局自定义指令 私有自定义指令 钩子函数 注意:fond-weight是粗细 ...

  9. 自学linux——17.selinux的了解及使用

    SElinux是强制访问控制(MAC)安全系统,是linux历史上最杰出的新安全系统.对于linux安全模块来说,SElinux的功能是最全面的,测试也是最充分的,这是一种基于内核的安全系统. 1.S ...

  10. Elgamal加密算法和数字签名

    简述:ElGamal公钥密码体制是由 T.ElGamal于 1985年提出的,直到现在仍然是一个安全性能良好的公钥密码体制.该算法既能用于数据加密也能用于数字签名,其安全性依赖于计算有限域上离散对数这 ...