本文学习AssertJ,一个开源的、社区驱动的测试库,可以写流畅的、丰富的Java测试断言,我们主要聚焦AssertJ-core提供的功能。
首先需要增加相应依赖,Spring Boot默认已经加载。
org.assertj
assertj-core
3.4.1
test
该依赖仅包括基本的java断言,包括Java 8特性,如果需要使用高级断言,需要单独增加额外的模块。对于Java7及以前版本需要使用2.x.x版本。读者可以选择合适版本或最新版本。
AssertJ提供一组类和工具方法,可以很容易写出流畅、优美的断言方法:
读者可以在其官网上查看所有有效模块。下面是从官网摘取的几个简单示例看看:
assertThat(frodo)
.isNotEqualTo(sauron)
.isIn(fellowshipOfTheRing);
assertThat(frodo.getName())
.startsWith("Fro")
.endsWith("do")
.isEqualToIgnoringCase("frodo");
assertThat(fellowshipOfTheRing)
.hasSize(9)
.contains(frodo, sam)
.doesNotContain(sauron);
上面示例仅为冰山一角,但可以让我们了解下AssertJ写断言的大致情况。
本节我们将集中于学习AssertJ并探索其可能性。引入相应依赖或jar包之后,应用仅需在测试类中增加一句静态导入语句:
import static org.assertj.core.api.Assertions.*;
写断言首先需要传入测试对象至Assertions.assertThat()
方法,然后跟上实际的断言方法。与其他库不同,下面代码没有实际断言任何内容,也永远不会产生失败的测试:
assertThat(anyRefenceOrValue);
如果利用IDE代码提示特性,写AssertJ断言将变得难以置信地容易,所有方法都是自描述的,下面截图来着IDEA:
我们看到有很多与字符串相关方法可以选择,下面看看这些API的详细应用。
对象可以使用多种方式进行比较,既可以两个对象进行比较也可以对象的字段进行比较。下面示例看Dog类的对象fido和fidosClone之间比较:
public class Dog {
private String name;
private Float weight;
// standard getters and setters
}
Dog fido = new Dog("Fido", 5.25);
Dog fidosClone = new Dog("Fido", 5.25);
也可以使用下面断言进行比较:
assertThat(fido).isEqualTo(fidosClone);
该对象引用之间比较会失败。如果比较其内容,可以使用isEqualToComparingFieldByFieldRecursively()
方法:
assertThat(fido).isEqualToComparingFieldByFieldRecursively(fidosClone);
当对两个对象fido和fidosClone进行按字段递归比较,两者是相等。有许多断言方法提供不同方式进行比较,还可以对其字段进行检查和断言。
布尔比较函数:
示例如下:
assertThat("".isEmpty()).isTrue();
对于Iterable/Array有多种断言方法判断其内容是否存在。最常见的是判断是否存在给定元素:
List list = Arrays.asList("1", "2", "3");
assertThat(list).contains("1");
或判断是否为空:
assertThat(list).isNotEmpty();
或如果List已给定元素开头:
assertThat(list).startsWith("1");
如果在一个对象上进行多个断言,可以很容易采用链接方式。下面示例首先检查列表是否为空,然后判断是否包括“1”元素,不包括空值,并且包括元素序列“2”、“3”:
assertThat(list)
.isNotEmpty()
.contains("1")
.doesNotContainNull()
.containsSequence("2", "3");
该类型还有很多其他可能的断言,读者可以自己查看官网文档。
字符类型断言一般涉及比较和检查字符是否来自Unicode表。请看实例:
assertThat(someCharacter)
.isNotEqualTo('a')
.inUnicode()
.isGreaterThanOrEqualTo('b')
.isLowerCase();
方法几乎都是自描述,不再解释。
类断言一般检查其字段和类的类型,注解是否存在、是否为final类。如果判断Runnable类是否为接口:
assertThat(Runnable.class).isInterface();
或者判断一个类是否从另一个类赋值:
assertThat(Exception.class).isAssignableFrom(NoSuchElementException.class);
File断言检查文件实例是否存在,是目录或文件,有一定内容,是否可读,具有特定扩展名。
下面示例执行一些列检查:
assertThat(someFile)
.exists()
.isFile()
.canRead()
.canWrite();
数值类型包括Double/Float/Integer及其他类型。断言主要比较数值在一定偏移量之内或之外。举例,检查两个数值在一定精度范围内是否相等:
assertThat(5.1).isEqualTo(5, withPrecision(1d));
注意这里使用withPrecision(Double offset) 方法生成偏移量对象。
流断言只有一个方法:
hasSameContentAs(InputStream expected),示例如下:
assertThat(given).hasSameContentAs(expected);
Map断言主要检查map是否包括特定项(key,value对),或key和value单独比较。示例如下:
assertThat(map)
.isNotEmpty()
.containsKey(2)
.doesNotContainKeys(10)
.contains(entry(2, "a"));
Throwable断言主要检查异常消息,栈跟踪,原因(cause)检查或验证。示例如下:
assertThat(ex).hasNoCause().hasMessageEndingWith("c");
为了更好描述断言,可以在断言中动态生成自定义描述,使用as方法,示例如下:
assertThat(person.getAge())
.as("%s's age should be equal to 100", person.getName())
.isEqualTo(100);
运行测试输出结果如下:
[tom's age should be equal to 100] expected:<100> but was:<27>
本文简要说明了AssertJ提供的各种断言方法,帮助我们更便捷地写各种测试断言,更多功能可参考官网。