Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE

1. Overview

JUnit becomes many developers’ first choice to perform unit tests on Java code. In real-world scenarios, one common testing requirement is to validate whether a given string conforms to a particular regular expression (regex) pattern.

In this tutorial, we’ll explore several approaches to assert regex matches in JUnit, empowering us to test our string patterns effectively.

2. Introduction to the Problem

The problem is quite simple: we want a natural and effective method to confirm that an input string aligns with a specific regex pattern. Ideally, we should also have a reliable approach to assert the opposite scenario, where an input string doesn’t match a regex pattern.

Let’s begin by exploring the widely-used JUnit 5 framework and learn how to perform assertions for regex pattern matches using its standard features. Additionally, we’ll discuss a potential pitfall when employing JUnit 5 for such assertions.

Beyond JUnit 5, there are convenient and supplementary test and assertion libraries that seamlessly integrate with JUnit 5. In this tutorial, we’ll focus on two of these popular external libraries. We’ll look at how to assert regex pattern matches within the context of these libraries, expanding our toolkit for efficient testing.

3. Using the Standard JUnit 5 Methods

JUnit 5 provides a series of frequently used assertions in the package org.junit.jupiter.api.Assertions, such as assertSame(), assertEquals(), and so on.

Yet, JUnit 5 lacks dedicated assertion methods like “assertMatches()” for regex pattern validation. Since the String.matches() method returns a boolean, we can make use of the assertTrue() method to ensure a string matches a regex pattern:

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

Unsurprisingly, if we want to assert a string doesn’t match a regex pattern, we can use the assertFalse() assertion:

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

4. Why We Shouldn’t Use the assertLinesMatch() Method for Regex Matching Tests

While we mentioned earlier that JUnit 5 lacks dedicated regex pattern assertion methods, some might disagree with this statement. JUnit 5 indeed provides the assertLinesMatch() method, which can verify regex pattern matches within lines of text, for example:

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

As the example above shows, since the method accepts two lists (the expected list and the actual list) of strings, we wrapped the regex pattern and the input string in lists, and the test passes.

However, it’s worth noting that it isn’t safe to test regex matches using the assertLinesMatch() method. An example can show it quickly:

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

In the example above, our input string and the regex pattern are the same: “.* at Baeldung$“. Obviously, the input doesn’t match the pattern since the input string ends with a ‘$‘ character instead of “Baeldung“. So, the assertFalse() assertion passes.

Then, we pass the same input and the regex pattern to the assertLinesMatch() method, and the assertion has passed! This is because assertLinesMatch() verifies each pair from the expected list and the actual list in three steps:

  1. If the expected string equals the actual string continue with the next pair
  2. Otherwise, treat the expected string as a regex pattern and check actualString.matches(expectedString). If the result is true, continue with the next pair
  3. Otherwise, if the expected string is a fast-forward marker, apply fast-forward actual lines accordingly and start from the first step

We won’t dive into the usage of the assertLinesMatches() method. As the steps above show, the regex pattern test is performed in step 2. In our example, the actual string, which is the input, and the expected string, the regex pattern, are equal. Therefore, the step 1 passed. That’s to say, the assertion passed without applying the regex-match check at all.

So, the assertLinesMatch() method isn’t the proper assertion method for validating regex pattern matches.

5. Using AssertJ’s matches() Method

With the popular AssertJ library, we can write fluent assertions quickly. AssertJ provides the matches() method to test regex patterns:

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

As the name implies, the doesNotMatch() method allows us to perform the negative test scenario:

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

6. Using Hamcrest’s matchesPattern() Method

Similarly, Hamcrest is another widely used testing framework. Also, it offers the matchesPattern() method for regex matching tests:

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

To perform a negative regex matching test, we can use not() to negate the Matcher created by matchesPattern():

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

7. Conclusion

In this article, we’ve explored different ways to assert regex pattern matches.

Two commonly used libraries, AssertJ and Hamcrest, offer dedicated regex matching test methods. On the other hand, JUnit 5’s assertTrue() combined with the String.matches() method can also achieve the same goal if we prefer to minimize external dependencies.

Additionally, we’ve discussed that we shouldn’t use JUnit 5’s assertLinesMatch() for regex pattern matching tests.

As always, the complete source code for the examples is available over on GitHub.

Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE
res – REST with Spring (eBook) (everywhere)
Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.