AssertJ快速启动

引入AssertJ依赖,请参考在项目中准备测试环境一节。

注意AssertJ Core 3.x需要Java 8以上版本。AssertJ Core 2.x需要Java 8以上版本。

1. 断言入口

1.1 使用Assertions入口类

AssertJorg.assertj.core.api.Assertions类为入口点。这个类提供了很多静态方法,供断言使用,其中最重要的是assertThat()方法,它是断言类的工厂,根据方法参数的类型不同而生成不同的断言类,从而分别提供一组特定的断言方法(例如为字符串型的参数提供一组校验方法,而为整数型参数提供另外一组校验方法)。下面是一些示例:

package yang.yu.tdd.assertj;

import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.List;

import static org.assertj.core.api.Assertions.*;

public class AssertJTest {

    @Test
    public void testString() {
        String sut = "I love you baby";
        assertThat(sut).startsWith("I love")
                .endsWith("baby")
                .contains("you")
                .contains("I", "love", "you")
                .doesNotContain("You")
                .containsIgnoringCase("You");
    }

    @Test
    public void testInt() {
        int sut = 3 + 4;
        assertThat(sut).isEqualTo(7)
                .isLessThan(8)
                .isGreaterThan(6)
                .isGreaterThanOrEqualTo(7);
    }

    @Test
    public void testList() {
        List<String> sut = Arrays.asList("I love you baby".split(" ").clone());
        assertThat(sut)
                .containsAnyOf("I", "love")
                .doesNotContain("Love")
                .containsExactly("I", "love", "you", "baby")
                .doesNotContainNull();
    }
}

针对不同的被检验对象提供类型特定的校验方法,正是AssertJ相比于其他断言库的核心优势所在。例如上面的例子中,testString()测试方法的被检验对象是一个字符串,可以校验的方法包括startsWith(), endsWith(), contains()等等;而testInt()测试方法的被检验对象是一个整数,可以校验的方法包括isEqualTo(), isLessThan(),isGreaterThanOrEqualTo()等等。利用IDE的代码提示功能,我们可以很容易地编写针对特定被检验对象的断言。其他的断言库如Hamcrest等,则明显缺乏这些能力。

AssertJ另一个优势就是流式断言:针对同一个被检验对象连续发起多个校验,而不是每次发起一个校验。

其他断言库的断言方法一般是双参数的:一个是期待的结果,一个是实际的执行结果,例如:

assertEquals(7, calculator.add(3, 4));

其中第一个参数是期待的值,第二个是测试执行的实际结果。

AssertJ的断言方法一般是单参数的:通过assertThat()工厂方法接受测试执行结果作为参数之后创建特定类型的断言类,后续一系列的断言方法就只需要接受预期值这么一个参数,所以写起来比较简便,而且可以流式拼接:

assertThat(calculator.add(3, 4)).isEqualTo(7)
        .isGreaterThanOrEqualTo(7);

1.2 实现WithAssertions接口

除了静态导入org.assertj.core.api.Assertions类的工厂方法之外,还可以让测试类实现org.assertj.core.api.WithAssertions类。因为WithAssertions接口直接提供了上述工厂方法的缺省实现(Java 8及以后的版本允许在接口中定义缺省方法),所以可以在测试类中直接使用这些工厂方法,无需静态导入。

package yang.yu.tdd.assertj;

import org.assertj.core.api.WithAssertions;
import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.List;

public class AssertJWithAssertionsTest implements WithAssertions {

    @Test
    public void testString() {
        String sut = "I love you baby";
        assertThat(sut).startsWith("I love")
                .endsWith("baby")
                .contains("you")
                .contains("I", "love", "you")
                .doesNotContain("You")
                .containsIgnoringCase("You");
    }
}

2. 断言描述

可以在任何断言的前面用as(String description, Object… args)方法添加断言描述。例如:

TolkienCharacter frodo = new TolkienCharacter("Frodo", 33, Race.HOBBIT);

// failing assertion, remember to call as() before the assertion!
assertThat(frodo.getAge()).as("check %s's age", frodo.getName())
                          .isEqualTo(100);

错误消息的形式会是:

[check Frodo's age] expected:<100> but was:<33>

3. 覆盖错误消息

可以在任何断言的前面采用overridingErrorMessage()withFailMessage()覆盖错误消息的内容。例如:

TolkienCharacter frodo = new TolkienCharacter("Frodo", 33, Race.HOBBIT);
TolkienCharacter sam = new TolkienCharacter("Sam", 38, Race.HOBBIT);
// failing assertion, remember to call withFailMessage/overridingErrorMessage before the assertion!
assertThat(frodo.getAge()).withFailMessage("should be %s", frodo)
                          .isEqualTo(sam);

上面的断言会失败并呈现错误消息,错误消息的形式:

java.lang.AssertionError: should be TolkienCharacter [name=Frodo, age=33, race=HOBBIT]

results matching ""

    No results matching ""