Integrating JUnit 5
Estimated time to read: 6 minutes
Running tests from the console¶
The JUnit Console Launcher allows tests to be launched from the command line. It is an executable JAR that comes with all required dependencies to run JUnit test.
Dependency Information¶
- Group ID: org.junit.platform
- Artifact ID: junit-platform-console-standalone
- Version: 1.x.x
Running Tests¶
The console launcher can be opened with the following command, java -jar junit-platform-console-standalone.jar
.
It takes additional options such as:
-cp ${PATH-TO-COMPILED-CLASSES}
, which is used for directing the JAR to compiled classes--scan-classpath
, which enables it to automatically look for methods with the test annotation
Argument Files¶
There can be system limitations with the maximum length of a command that can be run. The ConsoleLauncher supports argument files for long common lines.
Arguments can be entered into a file, separated by a new line or a space. Make sure to wrap arguments that include whitespace with single or double quotes.
# Comment
-- cp build/classes/java
-- include-classname ".*Test.*"
-- scan-classpath --details flat
The arguments within the file can then be invoked with the @<filename>
argument at the command line. For example, java -jar junit-platform-console-standalone.jar @args.txt
Running tests with Gradle¶
Gradle provides native support for executing JUnit 5 tests. Refer to 101 - Introducting JUnit 5 for a brief overview.
// Declare dependencies
dependencies {
testImplementation(platform('org.junit:junit-bom:5.x.x'))
testImplementation('org.junit.jupiter:junit-jupiter')
}
test {
useJUnitPlatform() // (1)
// Alternatively, this can be declared and other settings for the platform can be parsed in the build.gradle file
useJUnitPlatform {
includeTags 'v1', 'gift'
excludeTags 'conversion'
includeEngines 'junit-jupiter'
excludeEngines 'junit-vintage'
}
filter { // filter can be used to include / exclude specified methods also
includeTest 'io.entityfour.TestPackOne', 'testMethod1'
excludeTest 'io.entityfour.TestPackOne', 'testMethod2'
includeTestsMatching '*.TestPackOne*'
excludeTestsMatching 'io.entitiyfour.*'
}
// Configuration parameters for JUnit can be provided as JVM System Properties
systemProperty 'junit.jupiter.conditions.deactivate', 'io.entityfour.*'
systemProperties = [
'junit.jupiter.extensions.autodetection.enabled' : 'false',
'junit.jupiter.testinstance.lifecycle.default' : 'per_method'
]
}
1. Declare the JUnit platform usage
Running tests with Maven¶
Maven provides support for JUnit via the Maven Surefire Plugin for executing JUnit 5 tests. Refer to 101 - Introducting JUnit 5 for a brief overview.
By default, the Surefire plugin will automatically include all test classes with the following patterns:
**\Test\*.java
**\Test.java
**\Tests.java
**\TestCase.java
Further configuration can be done under the plugin configuration element within Maven's pom.xml file.
// ...
<build>
<plugins>
<plugin>
<artifiactId>maven-surefire-plugin</artifiactId>
<version>2.22.2</version>
<configuration>
<includes> // Include none default files and packages
<include>**/Test*.java</include>
<include>**/package/*.*</include>
</includes>
<excludes> // Exclude files and packages
<exclude>**/Test_Skip*.java</exclude>
</excludes>
<groups>v1, gift</groups> // Include specific tags
<excludedGroups>conversion</excludedGroups> // Exclude specific tags
<properties>
<configurationParameters> // JVM System Properties can be defined within this element
junit.jupiter.extensions.autodetection.enabled=false
junit.jupiter.testinstance.lifecycle.default=per_method
</configurationParameters>
</properties>
</configuration>
</plugin>
</plugins>
</build>
// ...
Include / Exclude tests with Tags¶
@tag
are annotations that are used to tag classes or methods with a specific string value. More than one @tag
can be applied to more than one element.
Classes / Methods¶
// ...
import org.junit.jupiter.api.Tag;
// ...
@Tag("v1")
@Tag("reward")
class TestRewards {
@Test
@Tag("fast")
void testRewardProgram() {
// ...
}
}
Interfaces¶
@tag
can also be used on interfaces. Classes then implement an annotated interface also inherit its semantics, thus inheriting the annotations.
@Tag('error')
@ExtendWith({ExceptionHandler.class})
public interface ErrorHandler {
// ...
}
Meta-annotations¶
A @tag
annotation can also meta-annotate another annotation, similar to @Test
and @ExtendWith
.
@Target({ElementType.Type, ElementType.Method})
@Retention(RetentionPolicy.RUNTIME)
@Test
@Tag("error")
@ExtendWith({ExceptionHandler.class})
public @interface TestWithErrorHandler() {
// ...
}
@Tag
Syntax Rules¶
The String value that the @Tag
annotation receives must abide to the following:
- A tag must not be null or blank
- Trailing whitespace characters are automatically trimmed
- A trimmed tag must not contain:
- Whitespace
- ISO Control Characters
- Reserved Characters
, ( ) & | !
Tag Expressions¶
In both Gradle and Maven, tag expressions can be used:
Operator | Description |
---|---|
! | Not |
& | And |
| | Or |
() | To modify precedence |
any() | To select all tests with any tags |
none() | To select all tests without any tags |
Example¶
v1 & !gift
- Selects all v1
tests but ignores gift
tests.
(gift | conversion) & (v1 | v2)
- Selects all gift
or conversion
tests that are also tagged as v1
or v2
Code Coverage¶
Code Coverage is the measured used to describe the degree to which the code of your program is covered by your tests. How many lines of code are executed by tests? 🤔
This metric is collected by a tool that traces the calls made by the tests of the application and reports the percentage of the code that is executed.
JaCoCo¶
JaCoCo is a popular code coverage library for Java. Visit JaCoCo for more information.
Maven¶
Using JaCoCo with Maven requires the following setup:
- JaCoCo added as a dependency to the pom.xml
- Add the JaCoCo agent as a 'prepare-agent' execution goal
- Create the report
The JaCoCo agent collects the coverage information, additionally the agent can be configured to generate a report from any phase of the build and at the report goal. Refer to Report below for more information.
// ...
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>x.y.z</version>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
// ...
JaCoCo can also be configured to ensure that a specific percentage of code coverage has been undertaken. This can be done by adding the following to the pom.xml:
<execution>
<id>jacoco-check</id>
<phase>test</phase>
<goals>
<goal>check</goal>
</goals>
<configuration>
<rules>
<rule>
<element>PACKAGE</element> // At the PACKAGE level,...
<limits>
<limit>
<counter>LINE</counter> // ...Check against line...
<value>COVEREDRATIO</value> // ...coverage ratio...
<minimum>0.70</minimum> // ...of 70%. Else, fail the build.
</limit>
</limits>
</rule>
</rules>
</configuration>
</execution>
Once configured in pom.xml. mvnw test
can be run to execute the test
phase. JaCoCo then outputs the following:
target/jacoco.exec
- Contains information collected by the JoCoCo agenttarget/site/jococo/*
- Contains the generated report in CSV, HTML and XML formats
Gradle¶
Using JaCoCo with Maven requires the following setup:
- JaCoCo added as a plugin to build.gradle
- Create the report
- Using
finalizedBy jacocoTestReport
- Using a
jacocoTestReport
task element
plugins {
id 'java'
id 'jacoco'
}
group 'io.entityfour'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
dependencies {
testImplementation(platform('org.junit:junit-bom:5.y.x'))
testImplementation('org.junit.jupiter:junit-jupiter')
}
test {
useJUnitPlatform()
finalizedBy jacocoTestReport // The report will be generated after the tests are run.
}
// jacocoTestReport {
// dependsOn test // Depends on the `test` task. Tests are required to run before generating the report.
// }
Once configured in build.gradle. gradlew test
can be run to execute the test
phase. JaCoCo then outputs the following:
build/jacoco/jacoco.exec
- Contains information collected by the JoCoCo agentbuild/reports/jacoco/test/html/*
- Contains the generated report in HTML
Coverage Report¶
The report shows the percentage of code covered by tests.
Expanding a package within the report will show code coverage for each class within it.
Expanding a class will show code coverage for each method also with a line by line breakdown.
- Green - Executed
- Red - Not executed
- Yellow - Branch not executed
Report Location¶
The output location of the report varies depending on if Gradle or Maven were used.
Under Gradle, the report is output to - build/reports/jacoco/test/html/*
Under Maven, the report is output to - target/site/jococo/*
The generated report is the same regardless of the build tool used.