spock 2.0 使用指南

x33g5p2x  于2021-09-19 转载在 其他  
字(7.3k)|赞(0)|评价(0)|浏览(425)

1.spock是什么

Spock是一个测试框架,它是JUnit的超集。Spock是相对新的框架,使用Groovy语法,Groovy语法简洁,Spock测试贴近自然语言,有更高可读性.
目前spock最新版本是2.0,对应的groovy版本为3.0
spock2.0是基于Junit5,当前Junit5与power mock存在兼容问题,所以spock2.0暂时不支持mock静态方法!
如果项目中需要使用到 静态方法的mock,可使用spock1.x .
spock2.0与spock1.x在功能使用上没有太大差别

2.spock例子

2.1 最简单的spock例子

class MathSpec extends Specification{
    def "最大数单元测试"(){
       expect :"最大数测试"
            Math.max(1,3)==3
    }
}

说明: 每个spock例子都要继承Specification.
expect分块 表示以下代码块是验证函数结果.
分块中每行的boolean值为true,则为成功,否则为失败
执行结果如下:

如果将上面的代码修改为:

def "最大数单元测试"(){
       expect :"最大数测试"
            Math.max(1,3)==1
    }

其执行结果如下:

可以从上图看出,spock会有详细的错误提示,上图告诉我们Math.max(1,3)的执行结果为3,所以执行结果为false

2.2 spock 基本范式例子

spock行为测试范式
spock的基本行为范式是:given-when-then
具体可见以下式子:

def "最大数单元测试"(){
        given:"准备环境数据"
            int i=1,j=3;
        when: "待验证函数"
            int result = Math.max(i,j);
        then: "结果验证"
          result == 3;
    }

除了 given,when,then之外还有where,and等分块,其具体说明如下:

分块替换功能限制
givensetup初始化函数,mock非必要
whenexpect执行待测试的函数when和then必须对成出现
thenexpect验证函数结果when和then可以被expect替换
where多套测试数据的检测spock的特性功能
and对其余块进行分隔说明非必要

2.3 spock批量验证

2.3.1 简单批量验证例子

spock的where分块,可以支持批量输入进行验证,例子如下:

def "批量最大数单元测试"(){
        when: "待验证函数"
            int result = Math.max(i,j);
        then: "结果验证"
          result == maxNum;
        where:"通过批量输入及输出参数,进行验证"
        i|j||maxNum
        1|3||3
        3|4||4
        5|2||5
    }

where分块中 || 是分隔输入与输出参数。
其中 i,j对应Math.max(i,j)中的两个输入参数;
maxNum对应语句 result == maxNum中的maxNum
spock对where中的每一组数据都代入到when中的语句进行执行,并调用then中的表达语句,来验证结果.

输出结果如下:

2.3.2 含表达式验证例子

def "批量最大数单元测试"(){
        when: "待验证函数"
            int result = Math.max(i,j);
        then: "结果验证"
          result == maxNum;
        where:"通过批量输入及输出参数,进行验证"
        i|j||maxNum
        1| 3 || Math.abs(-3)
        3| 4 ||4
        5| 2 ||5
    }

结果如下:

2.3.3 复合结果验证例子

准备测试基础类

@Data
public class Person {
    private String name;
    private String yearOfBirth;
    private String label;

    public String toString(){
       return  String.join(",", name,yearOfBirth,label);
    }
}
public class PersonService {
    public String getLabel(Person person){
        return Optional.ofNullable(person)
                .filter(p->Objects.nonNull(p.getYearOfBirth()) && p.getYearOfBirth().length()==4)
                .map(p->p.getYearOfBirth().substring(2,3)+"0后").orElse("");
    }
}

spock测试类:

def "批量复杂结果验证"() {
        setup: "类环境"
            PersonService service = new PersonService();
        when: "数据准备及函数执行"
            Person person = new Person(name: personName, yearOfBirth: personYear);
            //设置标签
            person.setLabel(service.getLabel(person));
        then: "验证方式"
            person.toString() == personInfo;
            person.label == personLabel;
        where: "批量输入,输出参数"
            personName | personYear || personInfo     | personLabel
            "张三"      | "1985"     || "张三,1985,80后" | "80后"
            "Tom"      | "2001"     || "Tom,2001,00后" | "00后"
            "王五"      | "2011"     || "王五,2011,10后" | "10后"
    }

结果:

2.4 mock例子

spock测试类

def "批量复杂结果验证"() {
        setup: "类环境"
            //mock PersonService
            PersonService service = Mock(PersonService);
        when: "数据准备及函数执行"
            Person person = new Person(name: personName, yearOfBirth: personYear);
            //覆盖getLabel方法实现,>>表示定义或返回方法结果
            service.getLabel(_) >> { Person p->p.getYearOfBirth()+"出生"}
            //设置标签
            person.setLabel(service.getLabel(person));
        then: "验证方式"
            person.toString() == personInfo;
            person.label == personLabel;
        where: "批量输入,输出参数"
            personName | personYear || personInfo     | personLabel
            "张三"      | "1985"     || "张三,1985,1985出生" | "1985出生"
    }

2.5 spring例子

基础类:

@Component
public class CustomerDao {
    @Override
    public String toString() {
        return "dao";
    }
}

@Component
@Data
public class CustomerService {
    @Autowired
    CustomerDao customerDao;

    @Override
    public String toString() {
        return customerDao.toString();
    }
}

applicationContext.xml配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
              http://www.springframework.org/schema/context
                http://www.springframework.org/schema/context/spring-context.xsd
            http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd">

    <context:component-scan base-package="com.spring" />

</beans>

spock测试例子:

@ContextConfiguration(locations = "classpath*:applicationContext.xml")
class BaseSpec  extends Specification{
}
class CustomerSpec extends BaseSpec{
    @Autowired
    CustomerService customerService;

    def "测试 spring service 调用"(){
       expect: "返回 dao"
        customerService.toString() == "dao"
    }
}

3. spock 2.0 的maven配置

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>TestSpock</artifactId>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <spring.version>5.2.5.RELEASE</spring.version>
        <spock.version>2.0-groovy-3.0</spock.version>
        <lombok.version>1.18.4</lombok.version>
        <groovy.version>3.0.8</groovy.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.codehaus.groovy</groupId>
            <artifactId>groovy-all</artifactId>
            <version>${groovy.version}</version>
            <type>pom</type>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.spockframework</groupId>
            <artifactId>spock-core</artifactId>
            <version>${spock.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.spockframework</groupId>
            <artifactId>spock-spring</artifactId>
            <version>${spock.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.version}</version>
        </dependency>

        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.3.0</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.gmavenplus</groupId>
                <artifactId>gmavenplus-plugin</artifactId>
                <version>1.4</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                            <goal>testCompile</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>

    </build>
</project>

相关文章