tl;dr
We show how to develop a regular expression driven by automated tests in JUnit 5. Download setup from github.com/JohannesFKnauf/regex-tdd-parameterized-junit5-example and start playing.
git clone https://github.com/JohannesFKnauf/regex-tdd-parameterized-junit5-example
mvn clean test
Regex Testing: Now for JUnit 5
It’s been a year since the article series about
In the meantime, the popularity of JUnit 5 has grown. It’s time to provide sample code.
Indeed, JUnit 5 will make parameterized tests a first-class citizen. It is a new native feature. However, the JUnit 5 User Guide still marks parameterized tests as experimental.
Providing data by @MethodSource
In order to implement the exact same pattern of 1 self-sufficient simple test class, we choose the @MethodSource
test data source over more complex alternatives. I recommend to read the JUnit 5 User Guide, Nicolai Parlog’s article or Ali Dehghani’s article on Baeldung, if you want to learn more.
@MethodSource
works by reading a Stream
of Arguments
’ from a static method result. The second annotation we need is @ParameterizedTest
, which replaces @Test
on a method.
package de.metamorphant.examples;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.stream.Stream;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
public class ParameterizedRegexTest {
private static final String REGEX = "[-+]?\\d+(\\.\\d+)?([eE][-+]?\\d+)?";
static Stream<Arguments> testCases() {
return Stream.of(
Arguments.of("", false, "empty string"),
Arguments.of("a", false, "single non-digit"),
Arguments.of("1", true, "single digit"),
Arguments.of("123", true, "integer"),
Arguments.of("-123", true, "integer, negative sign"),
Arguments.of("+123", true, "integer, positive sign"),
Arguments.of("123.12", true, "float"),
Arguments.of("123.12e", false, "float with exponent extension but no value"),
Arguments.of("123.12e12", true, "float with exponent"),
Arguments.of("123.12E12", true, "float with uppercase exponent"),
Arguments.of("123.12e12.12", false, "float with non-integer exponent"),
Arguments.of("123.12e+12", true, "float with exponent, positive sign"),
Arguments.of("123.12e-12", true, "float with exponent, negative sign")
);
}
@ParameterizedTest(name = "{index} ==> {2}: is {0} well-formed? {1}")
@MethodSource("testCases")
public void regexTest(String input, boolean isMatchExpected, String description) {
Boolean matches = input.matches(REGEX);
assertEquals(isMatchExpected, matches);
}
}
That’s all. Pretty simple, isn’t it? It stays ugly Java code, of course.
Build setup
Of course, we still need to set up the proper dependencies.
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>de.metamorphant.examples</groupId>
<artifactId>junit5-parameterized-regex-testing-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
</properties>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.6.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.6.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.6.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
</plugin>
</plugins>
</build>
</project>
A few notes:
org.junit.jupiter:junit-jupiter-params
is the only difference to an ordinary JUnit 5 project. This artifact contains the parameterized test features.- Pinning the surefire plugin to a recent version will already be familiar to you as a JUnit 5 user.
- Selecting Java 8 (or above) is needed to use the
Arguments.of(...)
static interface methods.
Run and confirm: It’s green.
mvn clean test
Post header background image by WikimediaImages from Pixabay.