1. 概述

JUnit 已成为许多开发人员进行Java代码单元测试的首选工具。在实际场景中,一个常见的测试需求是验证给定字符串是否符合特定的正则表达式(regex)模式。

在这篇教程中,我们将探讨在JUnit中使用多种方法来断言正则表达式匹配,从而有效地测试我们的字符串模式。

2. 问题介绍

问题很简单:我们需要一种自然且有效的方法来确认输入字符串与特定的正则表达式模式匹配。理想情况下,我们也应该有一个可靠的策略来断言输入字符串不匹配正则表达式模式。

首先,我们从广泛使用的JUnit 5框架 开始,学习如何使用其标准功能进行正则表达式模式匹配的断言。此外,还将讨论在使用JUnit 5进行此类断言时可能存在的潜在陷阱。

除了JUnit 5之外,还有一些方便且补充的测试和断言库,它们与JUnit 5无缝集成。在这篇教程中,我们将重点关注其中两个流行外部库。我们将探讨如何在这些库的上下文中断言正则表达式模式匹配,以扩大我们的高效测试工具箱。

3. 使用标准的JUnit 5方法

JUnit 5在org.junit.jupiter.api.Assertions包中提供了一系列常用的断言方法,如assertSame()assertEquals()等。

然而,JUnit 5缺乏专门用于正则表达式模式验证的断言方法,如“assertMatches()”。由于String.matches()方法返回一个布尔值,**我们可以使用assertTrue()方法确保字符串匹配正则表达式模式:

assertTrue("Java at Baeldung".matches(".* at Baeldung$"));

不出所料,如果我们想断言字符串不匹配正则表达式模式,可以使用assertFalse()断言:

assertFalse("something else".matches(".* at Baeldung$"));

4. 不应使用assertLinesMatch()方法进行正则匹配测试的原因

虽然我们之前提到JUnit 5缺乏专门的正则表达式模式断言方法,但有些人可能会对此表示异议。实际上,JUnit 5确实提供了[assertLinesMatch()](/junit-assertions#junit5-assertLinesMatch)方法,它可以验证文本行中的正则表达式匹配,例如:

assertLinesMatch(List.of(".* at Baeldung$"), List.of("Kotlin at Baeldung"));

如上所示,由于该方法接受两个字符串列表(预期列表和实际列表),我们将正则表达式模式和输入字符串包装在列表中,测试通过。

然而,值得注意的是,使用assertLinesMatch()方法进行正则匹配测试并不安全。一个例子可以迅速说明这一点:

assertFalse(".* at Baeldung$".matches(".* at Baeldung$"));
assertLinesMatch(List.of(".* at Baeldung$"), List.of(".* at Baeldung$"));

在上面的例子中,我们的输入字符串和正则表达式模式相同:“*.* at Baeldung$”。显然,输入字符串不匹配模式,因为输入字符串以字符“$”结尾,而不是“Baeldung”。所以,assertFalse()断言通过了。*

然后,我们将相同的输入和正则表达式模式传递给assertLinesMatch()方法,断言通过了!这是因为assertLinesMatch()方法在三步验证每个预期列表和实际列表中的对:

  1. 如果预期字符串等于实际字符串,则继续处理下一对
  2. 否则,将预期字符串视为正则表达式模式,并检查actualString.matches(expectedString)。如果结果为true,则继续处理下一对
  3. 否则,如果预期字符串是快进标记,根据需要应用实际行的快进并从第一步开始

我们不会深入讲解assertLinesMatch()方法的用法。如上述步骤所示,正则表达式模式的测试在步骤2中进行。在我们的示例中,实际字符串(即输入)和预期字符串(正则表达式模式)相等。因此,步骤1通过了。也就是说,根本没有执行正则匹配检查,断言就通过了。

因此,**assertLinesMatch()方法并不是验证正则表达式模式匹配的适当断言方法。**

5. 使用AssertJ的matches()方法

借助流行的AssertJ库,我们可以快速编写流畅的断言。AssertJ提供了matches()方法来测试正则表达式模式:

// assertThat() below is imported from org.assertj.core.api.Assertions
assertThat("Linux at Baeldung").matches(".* at Baeldung$");

名称所示,doesNotMatch()方法允许我们执行负面测试场景:

assertThat("something unrelated").doesNotMatch(".* at Baeldung$");

6. 使用Hamcrest的matchesPattern()方法

同样,Hamcrest 是另一个广泛使用的测试框架。它也提供了matchesPattern()方法用于正则匹配测试:

// assertThat() below is imported from org.hamcrest.MatcherAssert
assertThat("Computer science at Baeldung", matchesPattern(".* at Baeldung$"));

为了执行负向的正则匹配测试,我们可以使用not()否定由matchesPattern()创建的Matcher

assertThat("something unrelated", not(matchesPattern(".* at Baeldung$")));

7. 总结

在这篇文章中,我们探讨了不同的方法来断言正则表达式模式匹配。

两个常用的库,AssertJ和Hamcrest,提供了专门的正则表达式匹配测试方法。另一方面,如果偏好减少外部依赖,JUnit 5的assertTrue()结合String.matches()方法也能实现相同目标。

此外,我们讨论了不应使用JUnit 5的assertLinesMatch()方法进行正则表达式模式匹配测试。

一如既往,所有示例的完整源代码可在GitHub上找到。