在Springboot下使用Spock+Groovy进行测试

说明

前久介绍了一下怎么使用领域驱动设计(DDD)来搭建后端项目,现在来填坑讲下在Springboot下使用Spock+Groovy进行测试ヽ(ー_ー)ノ

介绍:

Groovy是一种基于JVM(Java虚拟机)的敏捷开发语言,它结合了Python、Ruby和Smalltalk的许多强大的特性,Groovy 代码能够与 Java 代码很好地结合,也能用于扩展现有代码。由于其运行在 JVM 上的特性,Groovy也可以使用其他非Java语言编写的库。

Spock是一个为groovy和java语言应用程序来测试和规范的一款全能型的单元测试框架。这个框架的突出点在于它美妙和高效表达规范的语言。来简单看一下写法:

    def '测试/getOtherById'() {
        given: '定义请求数据格式'
        other = new Other(xxxx)
        and: 'mock'
        otherService.getOtherById(_) >> other
        when: '向接口发请求'
        Other other1 = testController.getOtherById(a)
        then: '状态码为200'
        println(JSON.toJSONString(other1))
        Assert.assertEquals(c, other1.name)
        where:
        a | c
        1 | 'name'
    }

其实就是单测,不过可以模拟一些接口,在如今微服务的架构下,需要大量调用其他服务的接口,可我们不能等别人开发完了再去开发呀,所以我们先约定一些数据格式,然后编写我们的服务,调用他人服务时就Mock,这样就能测试我们的服务是否能够正常走通。

快速开始

建议:开始之前先看下groovy的基本语法,下面的地址的src>groovy>Hello.groovy可以直接运行用以学习groovy基础语法(本项目github项目地址->https://github.com/Yunlingfly/springboot-groovy-spock)(不需要单独安装Groovy环境了,pom里引了)

项目结构图:

在Springboot下使用Spock+Groovy进行测试_第1张图片

1 编写我们的待测试Controller

@RestController
public class OtherController {
    @Autowired
    IOtherService iOtherService;

    @RequestMapping(value = "/other")
    public Other getOtherById(Integer id) {
        return iOtherService.getOtherById(id);
    }
}

2 编写待测试Service接口和实现类

public interface IOtherService {
    Other getOtherById(Integer id);
}
@Service
public class OtherServiceImpl implements IOtherService {
    @Override
    public Other getOtherById(Integer id) {
        Other other = new Other();
        other.setId(id);
        other.setName("test");
        other.setEnabled(true);
        return other;
    }
}

3 编写测试

spock基础使用构造块如下,具体使用可以查看代码

given 定义数据
and 准备数据
when 待测试的函数
then 判断是否符合预期
expect 期望的行为,when-then的精简版
where 反复调用
thrown 如果在when方法中抛出了异常,则在这个子句中会捕获到异常并返回

def setup() {} 每个测试运行前的启动方法
package cn.yunlingfly.springbootgroovyspock.controller

import cn.yunlingfly.springbootgroovyspock.bean.Cc
import cn.yunlingfly.springbootgroovyspock.bean.Other
import cn.yunlingfly.springbootgroovyspock.service.IOtherService
import com.alibaba.fastjson.JSON
import org.junit.Assert
import org.junit.runner.RunWith
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.web.client.TestRestTemplate
import org.springframework.test.context.junit4.SpringRunner
import spock.lang.Shared
import spock.lang.Specification

// 使用Spock测试框架框架就不能使用下面的注解否则报错No runnable methods
//@RunWith(SpringRunner.class)
// 如果不RANDOM_PORT的话TestRestTemplate注入时会异常NoSuchBeanDefinitionException
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class TestControllerTests extends Specification {
    @Autowired
    private TestRestTemplate testRestTemplate

    TestController testController = new TestController()
    @Autowired
    IOtherService otherService;

    @Shared
    def Other other

    void setup() {
        otherService = Mock(IOtherService)
        testController.iOtherService = otherService
    }

    def '测试/getOtherById'() {
        // given 定义数据
        given: '定义请求数据格式'
        // 初始化我们测试接口返回的数据
        other = new Other()
        other.setId(1)
        other.setName("myName")
        other.setEnabled(true)

        // and 准备数据
        and: 'mock'
        otherService.getOtherById(_) >> other

        // when 待测试的函数
        when: '向接口发请求'
        Other other1 = testController.getOtherById(a)

        // then 判断是否符合预期
        then: '状态码为200'
        println(JSON.toJSONString(other1))
        Assert.assertEquals(c, other1.name)
//        other1.name == c

        // where 反复调用
        where:
        a | c
        1 | 'name'
        2 | 'myName'
    }
}

4 运行

测试方法上右键Run,可以看到我们的第二个测试用例出错了

在Springboot下使用Spock+Groovy进行测试_第2张图片

总结

单测基本上是无法避免的,既然无法避免,那就可以让单测变得更好玩~(ಥ_ಥ) ,这种写的方式可以很好地测试我们代码的健壮性,也能和别人同步开发(记得先约定数据结构!)

你可能感兴趣的:(Spring,Boot)