hi,你好!欢迎访问本站!登录
本站由网站地图腾讯云宝塔系统阿里云强势驱动
当前位置:首页 - 教程 - 杂谈 - 正文 君子好学,自强不息!

【spock】单测居然能够云云丝滑

2019-11-18杂谈搜奇网28°c
A+ A-

0. 为何人人都憎恶写单测

在之前的关于swagger文章里提到过,顺序员最憎恶的两件事,一件是他人不写文档,另一件就是本身写文档。这里假如把文档换成单元测试也一样建立。
每一个开辟人员都邃晓单元测试的作用,也都晓得代码覆盖率越高越好。高覆盖率的代码,相对来讲涌现 BUG 的几率就越低,在线上运转就越稳固,接的锅也就越少,就也不会畏惧测试同事倏忽的体贴。
既然这么多优点,为何还会憎恶他呢?最少在我看来,单测有以下几点让我喜好不起来的来由。
第一,要分外写许多许多的代码,一个高覆盖率的单测代码,每每比你要测试的,真正开辟的营业代码要多,以至是营业代码的好几倍。这让人以为难以接收,你想一想开辟 5 分钟,单测 2 小时是什么样的心境。而且并非单测写完就没事了,背面营业假如变动了,你所写的单测代码也要同步庇护。
第二,纵然你有谁人耐烦去写单测,然则在当前这个拼速率挤时刻的大环境下,会给你那末多写单测的时刻吗?写一个单测的时刻能够完成一个需求,你会怎样去选?
第三,写单测一般是一件很无趣的事,由于他比较死,重要目标就是为了考证,相比之下他更像是个体力活,没有真正写营业代码那种制造的成就感。写出来,考证不出bug很失踪,白写了,考证出bug又觉得本身是在打本身脸。

1. 为何人人又必需写单测

所以获得的结论就是不写单测?那末题目又来了,出来混迟早是要还的,上线出了题目,终究责任人是谁?不是提需求的产物、不是没发明题目的测试同砚,他们顶多就是连带责任。最该担任的肯定是写这段代码的你。迥殊是关于那些处置金融、生意业务、电商等息息相干营业的开辟人员,跟每行代码打交通的都是真金白银。每次明星搞事,微博就挂,已被传为笑谈,毕竟只是文娱相干,假如挂的是支付宝、微信,那用户就没有那末大的包涵度了。这些营业假如涌现严峻题目,轻则扫地出门,然后全部职业生涯背负这个污点,重则直接从面向对象开辟变成面向牢狱开辟。所以单元测试庇护的不仅仅是顺序,更庇护的是写顺序的你
末了得出了一个迫不得已的结论,单测是个让人又爱又恨的东西,是不想做但又不能不做的事变。虽然我们没办法转变要写单测这件事,然则我们能够转变怎样去写单元测试这件事。

2. SPOCK 能够帮你改良单测体验

固然,本文不是教你用歪门邪道的要领进步代码覆盖率。而是经由历程一个奇异的框架 spock 去进步你编写单元测试的效力。spock 这称号泉源,个人猜想是由于《星际迷航》的同名人物(封面图)。那末spock 是怎样进步编写单测的效力呢?我以为有以下几点:
第一,他能够用更少的代码去完成单元测试,让你能够越发专注于去考证结果而不是写单测代码的历程。那末他又是怎样做到少写代码这件事呢?本来他运用一种叫做 groovy 的魔法。
groovy 实际上是一门基于 jvm 的动态言语。能够简朴的明白成跑在 jvm 上的 python 或 js。说到这里,能够没有打仗过动态言语的同砚,对它们都邑有一个比较呆板的印象,太过于天真,很轻易涌现题目,且可庇护性差,所以有了那一句『动态一时爽,百口 xxx』的梗。起首,这些的确是他的题目,严厉的说是运用不当时才带来的题目。所以重要照样看运用的人。比方安卓范畴的官方依靠管理工具 gradle 就是基于 groovy 开辟的。
别的不要误以为我学这门框架,还要多学一门言语,本钱太大。实在大可不必忧郁,你假如会 groovy 固然更好,假如不会也没有关联。由于 groovy 是基于 java 的,所以完全能够放心大胆的运用 java 的语法,某些要用到的 groovy 独占的语法很少,而且背面都邑通知你。
第二,他有更好的语义化,让你的单测代码可读性更高。
语义化这个词能够不太好明白。举两个例子来讲吧,第一个是语义化比较好的言语 -- HTML。他的语法特性就是标签,差别的范例放在差别的标签里。比方 head 就是头部的信息,body 是主体内容的信息,table 就是表格的信息,关于没有编程履历的人来讲,也能够很轻易明白。第二个是语义化比较差的言语 -- 正则。他能够说基本上没有语义这类东西,由此致使的直接题目就是,纵然是你本身的写的正则,几天以后你都不晓得当时写的是什么。比以下面这个正则,你能猜出他是什么意义吗?(能够留言复兴)

((?:(?:25[0-5]|2[0-4]\d|[01]?\d?\d)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d?\d))

3. 明白 SPOCK 的魔法

3.1 引入依靠

        <!--假如没有使得 spring boot,以下包能够省略-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--引入spock 中心包-->
        <dependency>
            <groupId>org.spockframework</groupId>
            <artifactId>spock-core</artifactId>
            <version>1.3-groovy-2.5</version>
            <scope>test</scope>
        </dependency>
        <!--引入spock 与 spring 集成包-->
        <dependency>
            <groupId>org.spockframework</groupId>
            <artifactId>spock-spring</artifactId>
            <version>1.3-groovy-2.5</version>
            <scope>test</scope>
        </dependency>
        <!--引入 groovy 依靠-->
        <dependency>
            <groupId>org.codehaus.groovy</groupId>
            <artifactId>groovy-all</artifactId>
            <version>2.5.7</version>
            <scope>test</scope>
        </dependency>
申明

解释已标明,第一个包是 spring boot 项目须要运用的,假如你只是想运用 spock,只需最下面 3 个即可。个中第一个包 spock-core 供应了 spock 的中心功用,第二个包 spock-spring 供应了与 spring 的集成(不必 spring 的情况下也能够不引入)。 注重这两个包的版本号 -> 1.3-groovy-2.5。第一个版本号 1.3 实在代表是 spock 的版本,第二个版本号代表的是 spock 所要依靠的 groovy 环境的版本。末了一个包就是我们要依靠的 groovy 。

3.2 预备基本测试类

3.2.1 Calculator.java

/*
 * *
 *  * blog.coder4j.cn
 *  * Copyright (C) 2016-2019 All Rights Reserved.
 *
 */
package cn.coder4j.study.example.spock;

/**
 * @author buhao
 * @version Calculator.java, v 0.1 2019-10-30 10:34 buhao
 */
public class Calculator {

    /**
     * 加操纵
     *
     * @param num1
     * @param num2
     * @return
     */
    public static int add(int num1, int num2) {
        return num1 + num2;
    }

    /**
     * 整型除操纵
     *
     * @param num1
     * @param num2
     * @return
     */
    public static int divideInt(int num1, int num2) {
        return num1 / num2;
    }

    /**
     * 浮点型操纵
     * @param num1
     * @param num2
     * @return
     */
    public static double divideDouble(double num1,  double num2){
        return num1 / num2;
    }
}
申明

这是一个很简朴的盘算器类。只写了三个要领,一个是加法的操纵、一个整型的除法操纵、一个浮点范例的除法操纵。

3.3 最先单测 Calculator.java

3.3.1 建立单测类 CalculatorTest.groovy

class CalculatorTest extends  Specification {
    
}
申明

这里肯定要注重,之前我们已说了 spock 是基于 groovy 。所以单测类的后缀不是 .java 而** .groovy。万万不要建立成平常 java 类了。不然建立没有题目,然则写一些 groovy 语法会报错。假如你用的是 IDEA 能够经由历程以下体式格局建立,之前建立 Java 类我们都是挑选第一个选项,如今我们挑选第三个 Groovy Class** 就能够了。

别的就是 spock 的测试类须要继续 spock.lang.Specification 类。

3.3.2 考证加操纵 - expect

    def "test add"(){
        expect:
        Calculator.add(1, 1) == 2
    }
申明

def 是 groovy 的关键字,能够用来定义变量跟要领名。背面 "test add" 是你单元测试的称号,也能够用中文。末了重点申明的是 expect 这个关键字。
expect 字面上的意义是希冀,我们希冀什么样的事变发作。在运用别的单测框架时,与之相似的是 assert 。比方 _Assert.assertEquals(_Calculator.add(_1 + 1), 2) _如许,示意我们断言加操纵传入1 与 1 相加结果为 2。假如结果是如许则用例经由历程,假如不是则用例失利。这与我们上面的代码功用上完成一致。
expect 的语法意义就是在 expect 的内,一切表达式建立则考证经由历程,反之有任一个不建立则考证失利。这里引入了一个的观点。怎样明白 spock 的块呢?我们上面说 spock 有优越的语义化及更好的浏览性就是由于这个块的作用。能够类比成 html 中的标签。html 的标签的局限是两个标签之间,而 spock 更简约一点,从这个标签最先到下一个标签最先或代码完毕的处所,就是他的局限。我们只需看到 expect 这个标签就邃晓,他的局限内都是我们预期要获得的结果。

3.3.3 考证加操纵 - given - and

这里代码比较简朴,参数我只运用了一次,所以直接写死。假如想复用,我就得把这些参数抽成变量。这个时刻能够运用 spock 的 given 块。given 的语法意义相称因而一个初始化的代码块。

    def "test add with given"(){
        given:
        def num1 = 1
        def num2 = 1
        def result = 2

        expect:
        Calculator.add(num1, num2) == result
    }

固然你也能够像下面如许写,然则严峻不引荐,由于虽然能够到达一样的结果,然则不符合 spock 的语义。就像我们平常是在 head 内里引入 js、css,然则你在 body 或许任何标签里都能够引入,语法没有题目然则破坏了语义,不轻易明白与庇护。

    // 反倒
    def "test add with given"(){
        expect:
        def num1 = 1
        def num2 = 1
        def result = 2
        Calculator.add(num1, num2) == result
    }

假如你还想让语义更好一点,我们能够把参数与结果离开定义,这个时刻能够运用 and 块。它的语法功用能够明白成同他上面近来的一个标签。

    def "test add with given and"(){
        given:
        def num1 = 1
        def num2 = 1

        and:
        def result = 2

        expect:
        Calculator.add(num1, num2) == result
    }

3.3.4 考证加操纵 - expect - where

看了上面例子,能够以为 spock 只是语义比较好,然则没有少写几行代码呀。别急,下面我们就来看 spock 的一大杀器 where

    def "test add with expect where"(){
        expect:
        Calculator.add(num1, num2) == result

        where:
        num1    |   num2    |   result
        1       |   1       |   2
        1       |   2       |   3
        1       |   3       |   4
    }

where 块能够明白成预备测试数据的处所,他能够跟 expect 组合运用。上面代码里 expect 块内里定义了三个变量 num1、num2、result。这些数据我们能够在 where 块里定义。where 块运用了一种很像 markdown 中表格的定义要领。第一行或许说表头,列出了我们要传数据的变量称号,这里要与 expect 中对应,不能少然则能够多。别的行都是数据行,与表头一样都是经由历程 『 | 』 号分开。经由历程如许,spock 就会跑 3 次用例,离别是 1 + 2 = 2、1 + 2 = 3、1 + 3 = 4 这些用例。怎样?是否是很轻易,背面再扩大用例只需再加一行数据就能够了。 

3.3.5 考证加操纵 - expect - where - @Unroll

上面这些用例都是一般能够跑通的,假如是 IDEA 跑完以后会以下所示:

那末如今我们看看假如有效例不经由历程会怎样,把上面代码的末了一个 4 改成 5

    def "test add with expect where"(){
        expect:
        Calculator.add(num1, num2) == result

        where:
        num1    |   num2    |   result
        1       |   1       |   2
        1       |   2       |   3
        1       |   3       |   5
    }

再跑一次,IDEA 会涌现以下显现

左侧标注出来的是用例实行结果,能够看出来虽然有 3 条数据,个中 2 条数据是胜利,然则只会显现团体的胜利与否,所以显现未经由历程。然则 3 条数据,我怎样晓得哪条没经由历程呢?
右侧标注出来的是 spock 打印的的毛病日记。能够很清楚的看到,在 num1 为 1,num2 为 3,result 为 5 而且 他们之间的推断关联为 == 的结果是 false 才是准确的。 spock 的这个日记打印的是相称历害,假如是比较字符串,还会盘算非常字符串与准确字符串之间的婚配度,有兴致的同砚,能够自行测试。
嗯,虽然能够经由历程日记晓得哪一个用例没经由历程,然则照样以为有点贫苦。spock 也晓得这一点。所以他还同时供应了一个** @Unroll **注解。我们在上面的代码上再加上这个注解:

    @Unroll
    def "test add with expect where unroll"(){
        expect:
        Calculator.add(num1, num2) == result

        where:
        num1    |   num2    |   result
        1       |   1       |   2
        1       |   2       |   3
        1       |   3       |   5
    }

运转结果以下: 
经由历程增加** @Unroll** 注解,spock 自动把上面的代码拆分成了 3 个自力的单测测试,离别运转,运转结果更清楚了。
那末还能更清楚吗?固然能够,我们发明 spock 拆分后,每一个用例的称号实在都是你写的单测要领的称号,然后背面加一个数组下标,不是很直观。我们能够经由历程 groovy 的字符串语法,把变量放入用例称号中,代码以下:

    @Unroll
    def "test add with expect where unroll by #num1 + #num2 = #result"(){
        expect:
        Calculator.add(num1, num2) == result

        where:
        num1    |   num2    |   result
        1       |   1       |   2
        1       |   2       |   3
        1       |   3       |   5
    }

如上,我们在要领名后加了一句 #num1 + #num2 = #result。这里有点相似我们在 mybatis 或许一些模板引擎中运用的要领。# 号拼接声明的变量就能够了,实行后结果以下。

这下更清楚了。
别的一点,就是 where 默许运用的是表格的这类情势:

        where:
        num1    |   num2    |   result
        1       |   1       |   2
        1       |   2       |   3
        1       |   3       |   5

很直观,然则这类情势有一个弊病。上面 『 | 』 号对的这么整洁。都是我一个空格一个 TAG 按出来的。虽然语法不请求对齐,然则逼死强迫症。不过,幸亏还能够有另一种情势:

    @Unroll
    def "test add with expect where unroll arr by #num1 + #num2 = #result"(){
        expect:
        Calculator.add(num1, num2) == result

        where:
        num1 << [1, 1, 2]
        num2 << [1, 2, 3]
        result << [1, 3, 4]
    }

能够经由历程 『<<』 符(注重方向),把一个数组赋给变量,等同于上面的数据表格,没有表格直观,然则比较简约也不必斟酌对齐题目,这两种情势看个人喜好了。

3.3.6 考证整数除操纵 - when - then

我们都晓得一个整数除以0 会有抛出一个『/ by zero』非常,那末假如断言这个非常呢。用上面 expect 不太好操纵,我们能够运用另一个相似的块** when ... then**。

    @Unroll
    def "test int divide zero exception"(){
        when:
        Calculator.divideInt(1, 0)

        then:
        def ex = thrown(ArithmeticException)
        ex.message == "/ by zero"
    }

when ... then 一般是成对涌现的,它代表着当实行了 when 块中的操纵,会涌现 then 块中的希冀。比方上面的代码申清楚明了,当实行了 Calculator.divideInt(1, 0) 的操纵,就肯定会抛出 ArithmeticException 非常,而且非常信息是 / by zero

3.4 预备Spring测试类

上面我们已学会了 spock 的基本用法,下面我们将进修与 spring 整合的学问,起首建立几个用于测试的demo 类

3.4.1 User.java

/*
 * *
 *  * blog.coder4j.cn
 *  * Copyright (C) 2016-2019 All Rights Reserved.
 *
 */
package cn.coder4j.study.example.spock.model;

import java.util.Objects;

/**
 * @author buhao
 * @version User.java, v 0.1 2019-10-30 16:23 buhao
 */
public class User {
    private String name;
    private Integer age;
    private String passwd;

    public User(String name, Integer age, String passwd) {
        this.name = name;
        this.age = age;
        this.passwd = passwd;
    }

    /**
     * Getter method for property <tt>passwd</tt>.
     *
     * @return property value of passwd
     */
    public String getPasswd() {
        return passwd;
    }

    /**
     * Setter method for property <tt>passwd</tt>.
     *
     * @param passwd value to be assigned to property passwd
     */
    public void setPasswd(String passwd) {
        this.passwd = passwd;
    }

    /**
     * Getter method for property <tt>name</tt>.
     *
     * @return property value of name
     */
    public String getName() {
        return name;
    }

    /**
     * Setter method for property <tt>name</tt>.
     *
     * @param name value to be assigned to property name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * Getter method for property <tt>age</tt>.
     *
     * @return property value of age
     */
    public Integer getAge() {
        return age;
    }

    /**
     * Setter method for property <tt>age</tt>.
     *
     * @param age value to be assigned to property age
     */
    public void setAge(Integer age) {
        this.age = age;
    }

    public User() {
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return Objects.equals(name, user.name) &&
                Objects.equals(age, user.age) &&
                Objects.equals(passwd, user.passwd);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age, passwd);
    }
}

3.4.2 UserDao.java

/*
 * *
 *  * blog.coder4j.cn
 *  * Copyright (C) 2016-2019 All Rights Reserved.
 *
 */
package cn.coder4j.study.example.spock.dao;

import cn.coder4j.study.example.spock.model.User;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

/**
 * @author buhao
 * @version UserDao.java, v 0.1 2019-10-30 16:24 buhao
 */
@Component
public class UserDao {

    /**
     * 模仿数据库
     */
    private static Map<String, User> userMap = new HashMap<>();
    static {
        userMap.put("k",new User("k", 1, "123"));
        userMap.put("i",new User("i", 2, "456"));
        userMap.put("w",new User("w", 3, "789"));
    }

    /**
     * 经由历程用户名查询用户
     * @param name
     * @return
     */
    public User findByName(String name){
        return userMap.get(name);
    }
}

3.4.3 UserService.java

/*
 * *
 *  * blog.coder4j.cn
 *  * Copyright (C) 2016-2019 All Rights Reserved.
 *
 */
package cn.coder4j.study.example.spock.service;

import cn.coder4j.study.example.spock.dao.UserDao;
import cn.coder4j.study.example.spock.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @author buhao
 * @version UserService.java, v 0.1 2019-10-30 16:29 buhao
 */
@Service
public class UserService {

    @Autowired
    private UserDao userDao;

    public User findByName(String name){
        return userDao.findByName(name);
    }

    public void loginAfter(){
        System.out.println("登录胜利");
    }

    public void login(String name, String passwd){
        User user = findByName(name);
        if (user == null){
            throw new RuntimeException(name + "不存在");
        }
        if (!user.getPasswd().equals(passwd)){
            throw new RuntimeException(name + "暗码输入毛病");
        }
        loginAfter();
    }
}

3.4.3 Application.java

/*
 * *
 *  * blog.coder4j.cn
 *  * Copyright (C) 2016-2019 All Rights Reserved.
 *
 */

package cn.coder4j.study.example.spock;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

3.5 与 spring 集成测试

/*
 * *
 *  * blog.coder4j.cn
 *  * Copyright (C) 2016-2019 All Rights Reserved.
 *
 */

package cn.coder4j.study.example.spock.service

import cn.coder4j.study.example.spock.model.User
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import spock.lang.Specification
import spock.lang.Unroll

@SpringBootTest
class UserServiceFunctionTest extends Specification {

    @Autowired
    UserService userService

    @Unroll
    def "test findByName with input #name return #result"() {
        expect:
        userService.findByName(name) == result

        where:
        name << ["k", "i", "kk"]
        result << [new User("k", 1, "123"), new User("i", 2, "456"), null]

    }

    @Unroll
    def "test login with input #name and #passwd throw #errMsg"() {
        when:
        userService.login(name, passwd)

        then:
        def e = thrown(Exception)
        e.message == errMsg

        where:
        name    |   passwd  |   errMsg
        "kd"     |   "1"     |   "${name}不存在"
        "k"     |   "1"     |   "${name}暗码输入毛病"

    }
}

spock 与 spring 集成迥殊的简朴,只需你加入了开首所说的 spock-spring 和 spring-boot-starter-test。再于测试代码的类上加上 @SpringBootTest 注解就能够了。想用的类直接注入进来就能够了,然则要注重的是这里只能算功用测试或集成测试,由于在跑用例时是会启动 spring 容器的,外部依靠也必需有。很耗时,而且有时刻外部依靠当地也跑不了,所以我们一般都是经由历程 mock 来完成单元测试。

3.6 与 spring mock 测试

/*
 * *
 *  * blog.coder4j.cn
 *  * Copyright (C) 2016-2019 All Rights Reserved.
 *
 */

package cn.coder4j.study.example.spock.service

import cn.coder4j.study.example.spock.dao.UserDao
import cn.coder4j.study.example.spock.model.User
import spock.lang.Specification
import spock.lang.Unroll

class UserServiceUnitTest extends Specification  {

    UserService userService = new UserService()
    UserDao userDao = Mock(UserDao)

    def setup(){
        userService.userDao = userDao
    }

    def "test login with success"(){

        when:
        userService.login("k", "p")

        then:
        1 * userDao.findByName("k") >> new User("k", 12,"p")
    }

    def "test login with error"(){
        given:
        def name = "k"
        def passwd = "p"

        when:
        userService.login(name, passwd)

        then:
        1 * userDao.findByName(name) >> null

        then:
        def e = thrown(RuntimeException)
        e.message == "${name}不存在"

    }

    @Unroll
    def "test login with "(){
        when:
        userService.login(name, passwd)

        then:
        userDao.findByName("k") >> null
        userDao.findByName("k1") >> new User("k1", 12, "p")

        then:
        def e = thrown(RuntimeException)
        e.message == errMsg

        where:
        name        |   passwd  |   errMsg
        "k"         |   "k"     |   "${name}不存在"
        "k1"        |   "p1"     |   "${name}暗码输入毛病"

    }
}

spock 运用 mock 也很简朴,直接运用 Mock(类) 就能够了。如上代码 _UserDao userDao = Mock(UserDao) 。_上面写的例子中有几点要申明一下,以以下这个要领为例:

    def "test login with error"(){
        given:
        def name = "k"
        def passwd = "p"

        when:
        userService.login(name, passwd)

        then:
        1 * userDao.findByName(name) >> null

        then:
        def e = thrown(RuntimeException)
        e.message == "${name}不存在"

    }

given、when、then 不必说了,人人已很熟悉了,然则第一个 then 内里的 1 * userDao.findByName(name) >> null 是什么鬼?
起首,我们能够晓得的是,一个用例中能够有多个 then 块,关于多个希冀能够离别放在多个 then 中。
第二, 1 * xx 示意 希冀 xx 操纵实行了 1 次。1 * userDao.findByName(name)** 就表现当实行 userService.login(name, passwd) 时我希冀实行 1 次 userDao.findByName(name) 要领。假如希冀不实行这个要领就是_0 * xx,这在前提代码的考证中很有效,然后 >> null_ 又是什么意义?他代表当实行了 userDao.findByName(name) 要领后,我让他结果返回 null。由于 userDao 这个对象是我们 mock 出来的,他就是一个假对象,为了让后续流程按我们的主意举行,我能够经由历程『 >>』 让 spock 模仿返回指定数据。
第三,要注重第二个 then 代码块运用
${name} 援用变量,跟题目的 #name** 是差别的。

3.7 别的内容

3.7.1 大众要领

要领名 作用
setup() 每一个要领实行前挪用
cleanup() 每一个要领实行后挪用
setupSpec() 每一个要领类加载前挪用一次
cleanupSpec() 每一个要领类实行完挪用一次

这些要领一般用于测试最先前的一些初始化操纵,和测试完成后的清算操纵,以下:

    def setup() {
        println "要领最先前初始化"
    }

    def cleanup() {
        println "要领实行完清算"
    }

    def setupSpec() {
        println "类加载前最先前初始化"
    }

    def cleanupSpec() {
        println "所以要领实行完清算"
    }

3.7.2 @Timeout

关于某些要领,须要划定他的时刻,假如运转时刻超过了指定时刻就算失利,这时候能够运用 timeout 注解

    @Timeout(value = 900, unit = TimeUnit.MILLISECONDS)
    def "test timeout"(){
        expect:
        Thread.sleep(1000)
        1 == 1
    }

注解有两个值,一个是 value 我们设置的数值,unit 是数值的单元。

3.7.3 with

    def "test findByName by verity"() {
        given:
        def userDao = Mock(UserDao)

        when:
        userDao.findByName("kk") >> new User("kk", 12, "33")

        then:
        def user = userDao.findByName("kk")
        with(user) {
            name == "kk"
            age == 12
            passwd == "33"
        }

    }

with 算是一个语法糖,没有他之前我们要推断对象的值只能,user.getXxx() == xx。假如属性过量也是挺贫苦的,用 with 包裹以后,只需在花括号内直接写属性称号即可,如上代码所示。

4. 别的

4.1 完全代码

由于篇幅有限,没法贴完一切代码,完全代码已上传 github。

4.2 参考文档

本文在仰望了以下博主的出色博文后,再加上本身的进修总结加工而来,假如本文在看的时刻有不邃晓的处所能够看一下下方链接。

  1. Spock in Java 逐步爱上写单元测试
  2. 运用Groovy+Spock轻松写出更简约的单测
  3. Spock 测试框架的引见和运用详解
  4. Spock 基于BDD测试
  5. Spock 官方文档
  6. Spock测试框架
  7. spock-testing-exceptions-with-data-tables
  选择打赏方式
微信赞助

打赏

QQ钱包

打赏

支付宝赞助

打赏

  移步手机端
【spock】单测居然能够云云丝滑

1、打开你手机的二维码扫描APP
2、扫描左则的二维码
3、点击扫描获得的网址
4、可以在手机端阅读此文章
未定义标签

本文来源:搜奇网

本文地址:https://www.sou7.cn/282208.html

关注我们:微信搜索“搜奇网”添加我为好友

版权声明: 本文仅代表作者个人观点,与本站无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。请记住本站网址https://www.sou7.cn/搜奇网。

发表评论

选填

必填

必填

选填

请拖动滑块解锁
>>