在 JUnit 中断言正则表达式匹配

Posted

技术标签:

【中文标题】在 JUnit 中断言正则表达式匹配【英文标题】:Assert regex matches in JUnit 【发布时间】:2012-01-20 06:24:48 【问题描述】:

Ruby 的 Test::Unit 有一个很好的 assert_matches 方法,可以在单元测试中使用它来断言正则表达式匹配字符串。

在 JUnit 中有这样的东西吗?目前,我这样做:

assertEquals(true, actual.matches(expectedRegex));

【问题讨论】:

【参考方案1】:

JUnit 5 的更新,没有任何额外的库。

现在您可以按照https://junit.org/junit5/docs/5.0.1/api/org/junit/jupiter/api/Assertions.html#assertLinesMatch-java.util.List-java.util.List- 中的说明使用assertLinesMatch

创建断言是为了匹配多行文本,因此即使您尝试仅匹配一行,您也需要提供List。例如:

assertLinesMatch(List.of("Expected at the beginning.*"), List.of(contentUnderTest));

断言算法将尝试精确匹配,然后,如果失败,将使用String.match 将预期值解释为正则表达式。

重要提示:如果您的 contentUnderTest 包含多行,则正则表达式中的 .* 将不起作用(. 不匹配默认为换行符),因此您可能需要添加嵌入标志(https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html#DOTALL):

// Flag ?s means match new lines
assertLinesMatch(List.of("(?s)Expected at the beginning.*"), List.of(contentWithMultipleLines));

【讨论】:

【参考方案2】:

如果您使用assertThat() 和Hamcrest matcher 来测试正则表达式匹配,那么如果断言失败,您将收到一条很好的消息,指示预期的模式和实际文本。断言也会更流畅地阅读,例如

assertThat("FooBarBaz", matchesPattern("^Foo"));

使用 Hamcrest 2,您可以在 MatchesPattern.matchesPattern 找到 matchesPattern 方法。

【讨论】:

Hamcrest 2.0 现在内置了Matchers.matchesPattern(String):github.com/hamcrest/JavaHamcrest/blob/master/hamcrest-library/… @hinneLinks 所指内容的固定链接:github.com/hamcrest/JavaHamcrest/blob/…【参考方案3】:

Hamcrest中有对应的matcher:org.hamcrest.Matchers.matchesPattern(String regex)。

As development of Hamcrest stalled你不能使用最新的可用 v1.3:

testCompile("org.hamcrest:hamcrest-library:1.3")

相反,您需要使用新的开发系列(但仍然是dated by Jan 2015):

testCompile("org.hamcrest:java-hamcrest:2.0.0.0")

甚至更好:

configurations 
    testCompile.exclude group: "org.hamcrest", module: "hamcrest-core"
    testCompile.exclude group: "org.hamcrest", module: "hamcrest-library"

dependencies 
    testCompile("org.hamcrest:hamcrest-junit:2.0.0.0")

测试中:

Assert.assertThat("123456", Matchers.matchesPattern("^[0-9]+$"));

【讨论】:

我收到错误:在模块 jetified-hamcrest-core-1.3.jar (org.hamcrest:hamcrest-core:1.3) 和 jetified-java-hamcrest-2.0 中发现重复的类 org.hamcrest.BaseDescription .0.0.jar (org.hamcrest:java-hamcrest:2.0.0.0)【参考方案4】:

使用 assertj 的另一种选择。这种方法很好,因为它允许您直接传递模式对象。

import static org.assertj.core.api.Assertions.assertThat;
assertThat("my\nmultiline\nstring").matches(Pattern.compile("(?s)my.*string", Pattern.MULTILINE));

【讨论】:

【参考方案5】:

你可以使用 Hamcrest 和 jcabi-matchers:

import static com.jcabi.matchers.RegexMatchers.matchesPattern;
import static org.junit.Assert.assertThat;
assertThat("test", matchesPattern("[a-z]+"));

更多详情在这里:Regular Expression Hamcrest Matchers。

您将需要在类路径中使用这两个依赖项:

<dependency>
  <groupId>org.hamcrest</groupId>
  <artifactId>hamcrest-core</artifactId>
  <version>1.3</version>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>com.jcabi</groupId>
  <artifactId>jcabi-matchers</artifactId>
  <version>1.3</version>
  <scope>test</scope>
</dependency>

【讨论】:

我发现不需要hamcrest-core依赖【参考方案6】:

与 Ralph 的实现类似的匹配器已被 added 提供给官方 Java Hamcrest 匹配器库。不幸的是,它还没有在发布包中可用。课程在GitHub,不过如果你想看看的话。

【讨论】:

【参考方案7】:

您可以使用 Hamcrest,但您必须编写自己的匹配器:

public class RegexMatcher extends TypeSafeMatcher<String> 

    private final String regex;

    public RegexMatcher(final String regex) 
        this.regex = regex;
    

    @Override
    public void describeTo(final Description description) 
        description.appendText("matches regex=`" + regex + "`");
    

    @Override
    public boolean matchesSafely(final String string) 
        return string.matches(regex);
    


    public static RegexMatcher matchesRegex(final String regex) 
        return new RegexMatcher(regex);
    

用法

import org.junit.Assert;


Assert.assertThat("test", RegexMatcher.matchesRegex(".*est");

【讨论】:

【参考方案8】:

据我所知,没有其他选择。刚刚检查了assert javadoc 以确保。 不过,只是一点点变化:

assertTrue(actual.matches(expectedRegex));

编辑:自从 pholser 的回答以来,我一直在使用 Hamcrest 匹配器,也请检查一下!

【讨论】:

啊,是的,assertTrue() 肯定更好。我责怪 Eclipse 的自动完成功能,因为我对此一无所知。 ;) 当测试失败时,assertTrue 无法像 assertEqualsassertThat 那样为您提供详细信息 @Michael 当然可以。 assertTrue("Expected string matching '" +expectedRegex+ "'. Got: "+actual, actual.matches(expectedRegex));。不过它不如 Hamcrest 好。 @MikeValenty 如果您只是将一个值与is(true) 进行比较,那么assertThat 不会提供比assertTrue 更多的细节。要获得正确的错误消息,您需要一个不同的匹配器(或者您按照@MikeFHay 的建议手动构建消息)。 重要提示:string.matches() 可从 Java 版本 8 开始使用,在该版本中它不支持多行,即使使用相应的标志 (?m);那么您需要以旧的详细方式进行操作:Pattern.compile() 然后 matcher.find()【参考方案9】:

因为我也在寻找这个功能,所以我在 GitHub 上启动了一个名为 regex-tester 的项目。它是一个有助于在 Java 中轻松测试正则表达式的库(目前仅适用于 JUnit)。

这个库现在非常有限,但它确实有一个像这样工作的 Hamcrest 匹配器

assertThat("test", doesMatchRegex("tes.+"));
assertThat("test", doesNotMatchRegex("tex.+"));

更多关于如何使用 regex-tester 的信息是here。

【讨论】:

【参考方案10】:

它不是 JUnit,但这是 fest-assert 的另一种方式:

assertThat(myTestedValue).as("your value is so so bad").matches(expectedRegex);

【讨论】:

以上是关于在 JUnit 中断言正则表达式匹配的主要内容,如果未能解决你的问题,请参考以下文章

正则表达式中的断言(assertions)

正则表达式零宽断言

正则表达式 -断言

正则断言详解

mysql支不支持正则表达式里的零宽断言

如何使用 DFA 正则表达式匹配器实现正则表达式断言/环视(即 \b 样式字边界)