Contents

AssertJ 简介

1. 概述

在本文中,我们将探索AssertJ ——一个开源社区驱动的库,用于在 Java 测试中编写流畅和丰富的断言。

本文重点介绍名为AssertJ-core的基本 AssertJ 模块中可用的工具。

2. Maven依赖

为了使用 AssertJ,您需要在pom.xml文件中包含以下部分:

<dependency>
    <groupId>org.assertj</groupId>
    <artifactId>assertj-core</artifactId>
    <version>3.4.1</version>
    <scope>test</scope>
</dependency>

此依赖项仅涵盖基本的 Java 断言。如果要使用高级断言,则需要单独添加其他模块。

请注意,对于 Java 7 和更早版本,您应该使用 AssertJ 核心版本 2.xx

最新版本可以在这里 找到。

3. 简介

AssertJ 提供了一组类和实用方法,使我们能够轻松地编写流畅而漂亮的断言:

  • 标准 Java
  • Java 8
  • Guava
  • Joda Time
  • Neo4J and
  • Swing components

项目网站 上提供了所有模块的详细列表。

让我们从 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);

上面的例子只是冰山一角,但让我们大致了解如何使用这个库编写断言。

4. AssertJ 示例

在本节中,我们将专注于设置 AssertJ 并探索它的可能性。

4.1. 入门

使用类路径上的库 jar,启用断言就像向测试类添加单个静态导入一样简单:

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

4.2. 写断言

为了编写一个断言,您总是需要首先将您的对象传递给*Assertions.assertThat()*方法,然后再执行实际的断言。

重要的是要记住,与其他一些库不同,下面的代码实际上并没有断言任何东西,并且永远不会失败测试:

assertThat(anyRefenceOrValue);

如果您利用 IDE 的代码完成功能,由于其非常具有描述性的方法,编写 AssertJ 断言变得非常容易。这是 IntelliJ IDEA 16 中的样子:

/uploads/introduction_to_assertj/1.png IDE 的代码完成功能

如您所见,您有许多上下文方法可供选择,并且这些方法仅适用于String类型。让我们详细探讨一下这个 API 并看看一些具体的断言。

4.3. *Object *断言

可以通过各种方式比较*Object *以确定两个对象的相等性或检查对象的字段。

让我们看一下可以比较两个对象是否相等的两种方法。给定以下两个Dog对象fidofidosClone

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);

这将失败,因为isEqualTo()比较对象引用。如果我们想比较它们的内容,我们可以像这样使用isEqualToComparingFieldByFieldRecursively()

assertThat(fido).isEqualToComparingFieldByFieldRecursively(fidosClone);

FidofidosClone在逐个字段进行递归字段比较时是相等的,因为一个对象的每个字段都与另一个对象中的字段进行比较。

还有许多其他断言方法提供了不同的方法来比较和收缩对象以及检查和断言它们的字段。为了发现它们,请参阅官方AbstractObjectAssert 文档

4.4. *Boolean *断言

有一些简单的方法可用于真值测试:

  • isTrue()
  • isFalse()

让我们看看他们的行动:

assertThat("".isEmpty()).isTrue();

4.5. Iterable/Array断言

对于IterableArray有多种方法可以断言它们的内容存在。最常见的断言之一是检查IterableArray是否包含给定元素:

List<String> list = Arrays.asList("1", "2", "3");
assertThat(list).contains("1");

或者如果List不为空:

assertThat(list).isNotEmpty();

或者如果List以给定字符开头。例如“1”:

assertThat(list).startsWith("1");

请记住,如果您想为同一个对象创建多个断言,您可以轻松地将它们连接在一起。

这是一个断言示例,它检查提供的列表是否不为空、是否包含“1”元素、不包含任何空值并包含元素序列“2”、“3”:

assertThat(list)
  .isNotEmpty()
  .contains("1")
  .doesNotContainNull()
  .containsSequence("2", "3");

当然,这些类型存在更多可能的断言。为了发现它们,请参阅官方AbstractIterableAssert 文档

4.6. Character断言

字符类型的断言主要涉及比较,甚至检查给定字符是否来自Unicode表。

下面是一个断言示例,它检查提供的字符是否不是“a”、是否在 Unicode 表中、是否大于“b”并且是否为小写:

assertThat(someCharacter)
  .isNotEqualTo('a')
  .inUnicode()
  .isGreaterThanOrEqualTo('b')
  .isLowerCase();

有关所有字符类型断言的详细列表,请参阅AbstractCharacterAssert 文档

4.7. Class断言

Class类型的断言主要是关于检查其字段、Class类型、注释的存在和类终结性。

如果你想断言Runnable类是一个接口,你需要简单地写:

assertThat(Runnable.class).isInterface();

或者如果你想检查一个类是否可以从另一个类分配:

assertThat(Exception.class).isAssignableFrom(NoSuchElementException.class);

所有可能的Class断言都可以在AbstractClassAssert 文档 中查看。

4.8. *File *断言

File 断言都是关于检查给定的File实例是否存在、是目录还是文件、是否具有某些内容、是否可读或是否具有给定的扩展名。

在这里,您可以看到一个断言示例,该示例检查给定文件是否存在、是文件而不是目录、是否可读和可写:

 assertThat(someFile)
   .exists()
   .isFile()
   .canRead()
   .canWrite();

所有可能的类断言都可以在AbstractFileAssert 文档 中查看。

4.9. Double/Float/Integer断言

Double/Float/Integer和其他Number 类型

数字断言都是关于比较给定偏移量内或不外的数值。例如,如果您想根据给定的精度检查两个值是否相等,我们可以执行以下操作:

assertThat(5.1).isEqualTo(5, withPrecision(1d));

请注意,我们使用已经导入的 withPrecision(Double offset)辅助方法来生成Offset对象。

有关更多断言,请访问 AbstractDoubleAssert文档

4.10. InputStream断言

只有一个InputStream特定的断言可用:

  • hasSameContentAs(InputStream expected)

并在行动中:

assertThat(given).hasSameContentAs(expected);

4.11. *Map *断言

*Map *断言允许您检查映射是否分别包含某些条目、条目集或键/值。

在这里你可以看到一个断言的例子,它检查给定的映射是否不为空,包含数字键“2”,不包含数字键“10”并包含条目:key: 2, value: “a”:

assertThat(map)
  .isNotEmpty()
  .containsKey(2)
  .doesNotContainKeys(10)
  .contains(entry(2, "a"));

有关更多断言,请参阅AbstractMapAssert 文档

4.12. *Throwable *断言

*Throwable *断言允许例如:检查异常的消息、堆栈跟踪、原因检查或验证是否已经抛出异常。

让我们看一个断言的例子,它检查是否抛出了一个给定的异常并且有一个以“c”结尾的消息:

assertThat(ex).hasNoCause().hasMessageEndingWith("c");

有关更多断言,请参阅 AbstractThrowableAssert文档

5. 描述断言

为了达到更高的详细程度,您可以为断言创建动态生成的自定义描述。这样做的关键是*as(String description, Object… args)*方法。

如果你这样定义你的断言:

assertThat(person.getAge())
  .as("%s's age should be equal to 100", person.getName())
  .isEqualTo(100);

这是你在运行测试时会得到的:

[Alex's age should be equal to 100] expected:<100> but was:<34>

6. Java 8

AssertJ 充分利用了 Java 8 的函数式编程特性。让我们深入研究一个示例并查看它的实际效果。首先让我们看看我们在 Java 7 中是如何做到的:

assertThat(fellowshipOfTheRing)
  .filteredOn("race", HOBBIT)
  .containsOnly(sam, frodo, pippin, merry);

在这里,我们正在过滤关于种族 Hobbit 的集合,在 Java 8 中我们可以执行以下操作:

assertThat(fellowshipOfTheRing)
  .filteredOn(character -> character.getRace().equals(HOBBIT))
  .containsOnly(sam, frodo, pippin, merry);

我们将在本系列的后续文章中探讨 AssertJ 的 Java8 功能。以上示例取自 AssertJ 的网站