AssertJ快速启动
引入AssertJ
依赖,请参考在项目中准备测试环境一节。
注意AssertJ Core 3.x
需要Java 8
以上版本。AssertJ Core 2.x
需要Java 8
以上版本。
1. 断言入口
1.1 使用Assertions入口类
AssertJ
以org.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]