使用Spock 单元测试

一、什么是Spock

Spock 是一个测试框架,甚至可以说是一门语言他是基于Groovy开发的。它的语法完全遵循 BDD(行为驱动开发) 风格的结构。它是基于 Junit test runner 上开发但是又跟 Junit 完成不一样,同时集成了像 Jmock、Mockito 等语法表达风格于一体,使得它很简洁有很高的可读性。

 

 

 

 

二、Spock 优缺点

  •   语法清晰简单并且有很高的可读性

  •   不好的就是需要学习下Groovy 的语法,对Maven的配置不是很友好。但是在Gradle 中可以很好的支持

  

三、如何使用Spock

Maven 的配置

 

 

 

 

 

 

  •   Gmavenplus-plugin 插件可以让你的测试代码支持 Groovy 语法
  •   Surefire 插件 测试时只执行带有 Spec后缀的代码,这个必须是*Spec.java 而不是 groovy
  •   spock-core 就是 spock 的核心包
  •   byte-buddy 用来做动态代理,如果你需要测试的代码没有实现接口。spock 无法帮你mock,当然你也可以用 cliglib 代替

 

声明类

/**
 *
 * @author: serio.shi(苦参)
 * @create 2020/08/05 17:22
 * */
public class User {

    private int id;
    private String name;
    private int age;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

View Code

 

Dao 类

interface UserDao {
    public User get(int id);
    public User findByName(String name);
    public void createUser(User user);
}

View Code

 

UserService 类

/**
 *
 * @author: serio.shi(苦参)
 * @create 2020/08/05 17:23
 * */
public class UserService {

    private UserDao userDao;

    public UserService(UserDao userDao) {
        this.userDao = userDao;
    }

    public User findUser(int id){
        return userDao.get(id);
    }

    public void createUser(User user){
        User existing = userDao.findByName(user.getName());

        if(existing == null){
            userDao.createUser(user);
        } else{
            throw new RuntimeException(String.format("User with name %s already exists!", user.getName()));
        }
    }
}

View Code

 

测试 service的findUser 方法 mock dao的get 方法返回一个固定 user

 

是的你没有看错,它的方法名就是一个字符串(它有什么好处后面再讲)。它的语法很简单 given:、when:、then:、

setup 是它的元方法在测试用例执行前调用类似于 @before

  •  given 需要的一些变量参数
  •  when 就是需要测试的方法
  •  then 就是期待的结果

 

1 * dao.get(id) >> new User(id:id, name:”James”, age:27)

表示 dao.get(id) 方法将会被调用一次,并且让他返回 new User(id:id, name:”James”, age:27) 对象。并且期待它的结果是 result.id == 1、result.name == “James”、result.age == 27

 

在运行测试后

 

 

 

 

从图中我们可以看到,我们定义的方法名被打印出来。我们可以很方便的看到我们想要测试的内容成功了。

 

如果验证没有通过 Spock 将通过图表的方式告诉你哪里出问题,并且它会帮你把两个值的打印出来帮你做对比(经常有小伙伴写测试用例的时候把值打印出来用肉眼来识别错误)。我们把期待的id改为12再来试下。

 

 

 

 

 

 

  我们可以看到 Spock 提示你测试用例失败了,你的id 是1而期待的是12,当你点击 <Click to see difference> 的时候将会弹出一个框帮你做数据对比。简直是开发神器啊有木有!!!

 

Spock 还有一个神奇的参数化测试,类似于表格的形式填入参数和期待的结果

 

我们先在UserService类中加上以下代码:

Map datatable = [1:"jerry", 2:"tom", 3:"tommy", 4:"jack"]
public String getUser(int id){
    return datatable.get(id)
}

View Code

 

添加测试用例:

def "spock parameterized test demo"(){
    expect:
    service.getUser(id) == name
where: "some id with name"
    id || name
    1  || "jerry"
    2  || "tom"
    3  || "tommy"
    4  || "jack"
}

 

可以看到我们可以以更清晰的方式把入参跟结果描述出来,运行结果:

 

 

 

当前它还有很多的姿势待我们去解锁,本文只举例了简单的案例。

更多详情点击://spockframework.org/spock/docs/1.3/all_in_one.html#_introduction

 

四、小结

Spock 有着依赖少、运行快、语法简单、代码清晰等特点、本文只做简单的举例用于学习和记录