专栏首页7DGroup走进Java接口测试之流式断言库AssertJ

走进Java接口测试之流式断言库AssertJ

前言

在设计自动化接口 Cases 时,遵守的核心原则是3A(Arrange-> Actor ->Assert)原则;

断言工具是否强大直接影响到用例的执行效率,本文将介绍目前主流的一种流式断言神器:AssertJ。

AssertJ简介

什么是流式,常见的断言器一条断言语句只能对实际值断言一个校验点,而流式断言器,支持一条断言语句对实际值同时断言多个校验点,简单理解,即 AssertJ 断言是可以串接的。

AssertJ 是一个 Java 库,为 JDK 标准类型提供断言,可以与 JUnit,TestNG 或任何其他测试框架一起使用。 不同的 AssertJ 主要版本依赖于不同的 Java 版本:

  • AssertJ 3.x 需要 Java 8或更高版本
  • AssertJ 2.x 需要 Java 7或更高版本
  • AssertJ 1.x 需要 Java 6或更高版本

请注意,AssertJ 3.x包含所有AssertJ 2.x功能,并添加了Java 8特定功能(如 lambdas 的异常断言)

AssertJ 支持如下模块:

  • Core:AssertJ core is a Java library that provides a fluent interface for writing assertions.
  • Assertions generator:Use the Assertion Generator to create assertions specific to your own classes.
  • Guava:AssertJ assertions for Guava provides assertions for Guava types like Multimap, Table, Optional, Range or ByteSource.
  • Joda-Time:AssertJ assertions for Joda-Time provides assertions for Joda-Time types like DateTime and LocalDateTime.
  • DB:AssertJ-DB provides assertions to test data in a database.
  • Neo4j:Provides assertions for Neo4j 3 or higher.
  • Swing:AssertJ Swing is a Java library that provides a fluent interface for functional Swing UI testing.

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

地址:https://joel-costigliola.github.io/assertj/index.html

让我们从几个例子开始,直接来自 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使用

导包

SpringBoot 内置了 AssertJ,只需要导入 spring-boot-starter-test 依赖包

<dependencies>
        <!--引入效率插件-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!--引入测试包-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <!--引入testng测试框架-->
        <dependency>
            <groupId>org.testng</groupId>
            <artifactId>testng</artifactId>
            <version>6.14.3</version>
        </dependency>
    </dependencies>

入门使用

为了编写一个断言,你总是需要先将对象传递给 Assertions.assertThat() 方法,然后再按照实际的断言进行操作。

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

assertThat(anyRefenceOrValue);

如果你使用IDE的代码完成功能,由于其描述性非常强的方法,编写AssertJ 断言变得异常简单。下图就是它在 IntelliJIDEA 中的样子:

如图所见,有许多可供选择的上下文方法,并且这些方法仅适用于String类型。

对象断言

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

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Dog {
    private String name;
    private Float weight;

}

让我们看两种方法,我们可以比较两个对象的相等性。鉴于以下两个Dog对象 fido和 fidosClone

@Test(description = "对象断言1")
    public void whenComparingReferences_thenNotEqual() {

        // 实例化两个对象
        Dog fidos= new Dog("fidos",5.14f);
        Dog fidosClone = new Dog("fidosClone",5.14f);

        // 断言两个对象引用
        assertThat(fidos).isNotEqualTo(fidosClone);

    }

isEqualTo() 是比较对象引用,所以会执行失败。如果我们想要比较它们的内容,我们可以使用 isEqualToComparingFieldByFieldRecursively()

@Test(description = "对象断言2")
    public void whenComparingFields_thenEqual() {
        // 实例化两个对象
        Dog fido = new Dog("Fido", 5.15f);
        Dog fidosClone = new Dog("Fido", 5.15f);

        // 断言两个对象内容
        assertThat(fido).isEqualToComparingFieldByFieldRecursively(fidosClone);
    }

当通过字段比较执行递归字段时,Fido和fidosClone是相等的,因为一个对象的每个字段与另一个对象中的字段进行比较。

还有许多其他断言方法提供了比较和收缩对象以及检查和断言其字段的不同方法。具体请参阅官方的 AbstractObjectAssert API。

布尔断言

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

  • isTrue()
  • isFalse()

举个例子:

@Test(description = "布尔断言")
    public void whenisEmpty_isTrue() {
        // 实例化对象
        Dog fido = new Dog("Fido", 5.15f);

        // 断言字段是否为空
        assertThat(fido.getName().isEmpty()).isTrue();
    }

Iterable/Array断言

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

或者如果 List 不为空:

assertThat(list).isNotEmpty();

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

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

如果要为同一对象创建多个断言,可以轻松地将它们连接在一起。 下面是一个断言示例,它检查提供的列表是否为空,包含“1”元素,不包含任何空值并包含元素序列“2”,“3”:

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

当然,对于那些类型存在更多可能的断言 。具体请参阅官方的 AbstractIterableAssert API

完整示例:

@Test(description = "Iterable/Array断言1")
    public void whenCheckingForElement_thenContains(){
        List<String> list = Arrays.asList("1", "2", "3");

        // 断言是否包含给定元素
        assertThat(list).contains("1");
    }

    @Test(description = "Iterable/Array断言2")
    public void whenCheckingForElement_thenMultipleAssertions() {
        List<String> list = Arrays.asList("1", "2", "3");

        // 断言list不为空
        assertThat(list).isNotEmpty();
        // 断言list以给定字段开头
        assertThat(list).startsWith("1");
        // 断言list不包含null
        assertThat(list).doesNotContainNull();
        // 多个断言
        assertThat(list).isNotEmpty().contains("1").startsWith("1").doesNotContainNull().containsSequence("2", "3");
    }

字符断言

字符类型的断言主要涉及比较,甚至检查给定字符是否来自 Unicode 表。 下面是一个断言示例,它检查提供的字符是否不是 'a',在 Unicode 表中,是否大于 'b' 并且是小写的:

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

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

完整示例:

@Test(description = "字符断言")
    public void whenCheckingCharacter_thenIsUnicode() {
        char someCharacter = 'c';

        // 断言字符是否不是 'a',在 Unicode 表中,是否大于 'b' 并且是小写的
        assertThat(someCharacter).isNotEqualTo('a').inUnicode().isGreaterThanOrEqualTo('b').isLowerCase();
    }

类断言

Class 类型的断言主要是检查其字段,类类型,注释的存在和类的最终性。

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

assertThat(Runnable.class).isInterface();

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

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

可以在 AbstractClassAssert API 中查看所有可能的类断言。

完整示例:

@Test(description = "类断言1")
    public void whenCheckingRunnable_thenIsInterface() {
        // 断言Runnable类是一个接口
        assertThat(Runnable.class).isInterface();
    }

    @Test(description = "类断言2")
    public void whenAssigningNSEExToException_thenIsAssignable(){
        // 断言一个类是否可以从另一个类中分配
        assertThat(Exception.class).isAssignableFrom(NoSuchElementException.class);
    }

文件断言

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

在这里断言的示例,该断言检查给定文件是否存在,是文件而不是目录,可读写的:

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

可以在 AbstractFileAssert API 中查看所有可能的类断言。

完整示例:

@Test(description = "文件断言")
    public void whenCheckingFile_then() throws IOException {
        final File someFile = File.createTempFile("aaa", "bbb");
        someFile.deleteOnExit();

        // 断言文件是否存在,是文件而不是目录,可读写的
        assertThat(someFile).exists().isFile().canRead().canWrite();
    }

Double/Float/Integer断言

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

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

请注意,我们使用已导入的 withPrecision(双偏移)辅助方法来生成偏移对象。

有关更多断言,请访问 AbstractDoubleAssert API。

InputStream断言

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

  • hasSameContentAs(预期的 InputStream)

使用方法:

assertThat(given).hasSameContentAs(expected);

完整示例:

@Test(description = "InputStream断言")
    public void whenCheckingIS_then() {
        InputStream given = new ByteArrayInputStream("foo".getBytes());
        InputStream expected = new ByteArrayInputStream("foo".getBytes());

        // 断言是否预期的 InputStream
        assertThat(given).hasSameContentAs(expected);
    }

Map断言

Map 断言允许你分别检查 Map 是否包含某些条目,条目集或键/值。 你可以看到断言的示例,该断言检查给定的Map是否为空,包含key “2”,不包含数字键“10”并包含条目:key:2,value:“a”:

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

有关更多断言,请参阅 AbstractMapAssert API。

完整示例:

@Test(description = "Map断言")
    public void whenGivenMap_then() {
        Map<Integer, String> map = Maps.newHashMap(2, "a");

        // 断言Map是否为空,包含key “2”,不包含key “10” 并包含元素:key:2,value:“a”
        assertThat(map).isNotEmpty().containsKey(2).doesNotContainKeys(10).contains(entry(2, "a"));
    }

Throwable 断言

Throwable 的断言允许例如:检查异常的信息,踪迹,原因检查或者异常被抛出已验证。

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

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

有关更多断言,请参阅 AbstractThrowableAssert API。

完整示例:

@Test(description = "Throwable断言")
    public void whenGivenException_then() {
        Exception ex = new Exception("abc");

        // 断言是否抛出了给定的异常并且消息以“c”结尾
        assertThat(ex).hasNoCause().hasMessageEndingWith("c");
    }

描述断言

为了获得更高的详细级别,你可以为断言创建动态生成的自定义描述。 这样做的关键是 as(String description,Object ... args)方法。

如果你定义这样的断言:

assertThat(fidos.getWeight())
.as("%s's age should be equal to 5.15f")
.isEqualTo(5.15f);

这是运行测试时的结果:

org.junit.ComparisonFailure: [%s's age should be equal to 5.15f] 
Expected :5.1[5]f
Actual   :5.1[4]f

完整示例:

@Test(description = "描述断言")
    public void whenRunningAssertion_thenDescribed() throws Exception {
        Dog fidos= new Dog("fidos",5.14f);

        assertThat(fidos.getWeight()).as("%s's age should be equal to 5.15f").isEqualTo(5.15f);
    }

小结

在本文中,我们简要探讨了AssertJ 为核心Java类型提供最流行的流式断言的使用方法。

本文代码:

https://github.com/7DGroup/Java-API-Test-Examples

延伸阅读:

秒懂HTTPS接口(接口测试篇)

走进Java接口测试之Mock(概念篇)

走进Java接口测试之测试框架TestNG

走进Java接口测试之效率插件lombok

走进Java接口测试之接口管理工具Swagger2

走进Java接口测试之测试报告ExtentReport

走进Java接口测试之服务端测试报告Klov ExtentReports

走进Java接口测试之简单快速的Mock Server Moco

走进Java接口测试之流行框架SpringBoot(概念篇)

走进Java接口测试之持久层框架Spring-data-jpa

走进Java接口测试之使用JavaMailSender发送邮件

走进Java接口测试之日志框架Logback

走进Java接口测试之AOP统一日志记录

本文分享自微信公众号 - 7DGroup(Zee_7DGroup),作者:左泽位

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-01-21

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • [性能测试实战30讲」之问题问答整理八、九、十

    HTTP 的 GET 和 POST 请求,在后端处理中有什么不同?断言的作用是什么?如何使用断言呢?

    高楼Zee
  • [性能测试实战30讲」之问题问答整理七

    你也许听过这样一句至理名言:“计算机科学领域里的任何问题,都可以通过引入一个中间层来解决”。TCP/IP 协议栈是这样,而代理也是这样。

    高楼Zee
  • 性能工具之Jmeter小白入门系列之二

    在上一讲中简单的介绍了Jmeter的安装与Http Requet请求,在实际工作,咱们对工具的使用还需咱们进一步学习与操作才能掌握;

    高楼Zee
  • JMeter专题系列(五)检查点

    检查点:我们对用户名和密码进行了参数化,那么怎样来判断jmeter有没有正确调用t.dat里面的文件呢。当然,我们可以从结果图表中查看。但我还是想在“登录”这个...

    流柯
  • soapUI 接口测试断言

    断言的功能不言而喻, 是指定的restful api是否正常,判断它的响应值是否符合预期标准.

    louiezhou001
  • Jmeter系列(18)- 断言Assertions 的入门介绍

    https://www.cnblogs.com/poloyy/category/1746599.html

    小菠萝测试笔记
  • Jmeter(二十一) - 从入门到精通 - JMeter断言 - 上篇(详解教程)

      最近由于宏哥在搭建自己的个人博客可能更新的有点慢。断言组件用来对服务器的响应数据做验证,常用的断言是响应断言,其支持正则表达式。虽然我们的通过响应断言能够完...

    北京-宏哥
  • 性能测试-Jmeter断言(Assertion)

    使用断言的目的:用于检查测试中得到的响应数据等是否符合预期,用以保证性能测试过程中的数据交互与预期一致。在request的返回层面增加一层判断机制;因为requ...

    用户6367961
  • TestNg中的断言你真的了解吗

    在执行自动化测试脚本的时候,我们需要自动判断测试脚本执行完成后的实际结果是否与预期结果一致,这个时候就需要在程序运行之前写入断言,判断当前程序执行后是否正常。

    软件测试君
  • Jmeter(二十二) - 从入门到精通 - JMeter

    断言组件用来对服务器的响应数据做验证,常用的断言是响应断言,其支持正则表达式。虽然我们的通过响应断言能够完成绝大多数的结果验证工作,但是JMeter还是为我们提...

    北京-宏哥

扫码关注云+社区

领取腾讯云代金券