Setting up JUnit 6 with Maven and Gradle correctly is more than adding one dependency. You need the right plugin versions, the right configuration flags, and the right test source layout so tests are discovered, executed, and reported correctly every time. This guide covers every configuration option from a basic single-module project to advanced multi-module and CI-ready setups.
If you are brand new to JUnit 6, start with Getting Started with JUnit 6 first. This post goes deeper into build tool specifics.
Part 1: JUnit 6 with Maven
Step 1 — The Core Dependency
Add junit-jupiter to your pom.xml. This single aggregator pulls in the API, params module, and engine in one shot:
<properties>
<junit.version>6.1.1</junit.version>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencies>
<!-- JUnit Jupiter aggregator: API + Params + Engine -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
Step 2 — Maven Surefire Plugin (Unit Tests)
The Maven Surefire Plugin runs unit tests during the test phase. You must use a 3.x version (3.2.5 or higher recommended) — JUnit 6 no longer supports Surefire/Failsafe older than 3.0.0:
<build>
<plugins>
<!-- Surefire: runs tests in the 'test' lifecycle phase -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.5</version>
<configuration>
<!-- Show test output in the console during build -->
<useFile>false</useFile>
<!-- Include these naming patterns for test discovery -->
<includes>
<include>**/*Test.java</include>
<include>**/*Tests.java</include>
<include>**/Test*.java</include>
</includes>
</configuration>
</plugin>
</plugins>
</build>
Step 3 — Maven Failsafe Plugin (Integration Tests)
For integration tests (tests that start a server, connect to a database, etc.), use the Failsafe Plugin. By convention, integration test classes end with IT:
<!-- Failsafe: runs integration tests in 'verify' phase -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>3.2.5</version>
<executions>
<execution>
<goals>
<!-- 'integration-test' runs the tests -->
<goal>integration-test</goal>
<!-- 'verify' checks the results and fails the build if needed -->
<goal>verify</goal>
</goals>
</execution>
</executions>
<configuration>
<!-- Integration tests match *IT.java by convention -->
<includes>
<include>**/*IT.java</include>
</includes>
</configuration>
</plugin>
Run integration tests with: mvn verify
Step 4 — Running Tests from Maven CLI
# Run all unit tests
mvn test
# Run a specific test class
mvn test -Dtest=CalculatorTest
# Run a specific test method
mvn test -Dtest=CalculatorTest#addingTwoPositiveNumbers
# Skip tests entirely (not recommended in CI)
mvn package -DskipTests
# Run integration tests
mvn verify
# Run only tests tagged with "fast"
mvn test -Dgroups=fast
# Exclude tests tagged with "slow"
mvn test -DexcludedGroups=slow
Complete Maven pom.xml Example
<?xml version="1.0" encoding="UTF-8"?>
<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>com.example</groupId>
<artifactId>junit6-maven-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<junit.version>6.1.1</junit.version>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.5</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>3.2.5</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Part 2: JUnit 6 with Gradle
Groovy DSL (build.gradle)
// build.gradle — Groovy DSL
plugins {
id 'java'
}
group = 'com.example'
version = '1.0-SNAPSHOT'
java.sourceCompatibility = JavaVersion.VERSION_17
repositories {
mavenCentral()
}
dependencies {
// JUnit Jupiter aggregator (API + Params + Engine)
testImplementation 'org.junit.jupiter:junit-jupiter:6.1.1'
}
test {
// REQUIRED: activates the JUnit Platform test engine
useJUnitPlatform()
// Show individual test results in the console
testLogging {
events 'passed', 'failed', 'skipped'
showStandardStreams = true
}
// Fail the build if no tests ran (catches misconfigured projects)
failIfNoSpecifiedTests = false
}
Kotlin DSL (build.gradle.kts)
// build.gradle.kts — Kotlin DSL
plugins {
java
}
group = "com.example"
version = "1.0-SNAPSHOT"
java.sourceCompatibility = JavaVersion.VERSION_17
repositories {
mavenCentral()
}
dependencies {
testImplementation("org.junit.jupiter:junit-jupiter:6.0.0")
}
tasks.test {
// REQUIRED: activates the JUnit Platform test engine
useJUnitPlatform()
testLogging {
events("passed", "failed", "skipped")
}
}
Running Tests from Gradle CLI
# Run all tests
./gradlew test
# Run a specific test class
./gradlew test --tests "com.example.CalculatorTest"
# Run a specific test method
./gradlew test --tests "com.example.CalculatorTest.addingTwoPositiveNumbers"
# Run only tests tagged with "fast"
./gradlew test -Pgroups=fast
# Re-run tests even if nothing changed (disables caching)
./gradlew test --rerun-tasks
# Show test output continuously (useful in CI)
./gradlew test --info
Part 3: Multi-Module Project Setup
In a multi-module Maven project, define JUnit 6 in the parent POM’s dependencyManagement section so child modules inherit the version automatically:
<!-- parent/pom.xml -->
<dependencyManagement>
<dependencies>
<!-- BOM import: manages all JUnit 6 module versions together -->
<dependency>
<groupId>org.junit</groupId>
<artifactId>junit-bom</artifactId>
<version>6.1.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<!-- child/pom.xml — no version needed, inherited from BOM -->
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
Part 4: Filtering Tests by Tag
JUnit 6 lets you tag tests with @Tag and then include or exclude them at build time. This is extremely useful for separating fast unit tests from slow integration tests.
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
class OrderServiceTest {
// Tag this test as 'fast' — runs in every build
@Test
@Tag("fast")
void creatingOrderSetsStatusToPending() {
// fast, no I/O
}
// Tag this test as 'slow' — only runs when explicitly requested
@Test
@Tag("slow")
void sendingOrderConfirmationEmailDelivered() {
// slow, hits email server
}
}
Configure Maven Surefire to only run fast tests during normal builds:
<configuration>
<!-- Only run tests tagged 'fast' -->
<groups>fast</groups>
<!-- Or exclude tests tagged 'slow' -->
<!-- <excludedGroups>slow</excludedGroups> -->
</configuration>
Part 5: IDE Integration
IntelliJ IDEA
IntelliJ IDEA has native JUnit 6 support. After adding the Maven/Gradle dependency:
- Click the green â–¶ icon next to any
@Testmethod to run it individually - Right-click the test class → Run All Tests
- Use Run → Edit Configurations to create a reusable run config with tag filters
- The test results panel shows a full tree view with pass/fail/skip indicators
Eclipse
Eclipse supports JUnit 6 via the built-in JUnit plug-in. Right-click the project or test class → Run As → JUnit Test. For Maven projects, ensure m2e (Maven Integration for Eclipse) is installed.
VS Code
Install the Extension Pack for Java which includes the Test Runner for Java. Tests appear in the Testing panel (beaker icon) with run/debug controls per method. Gradle and Maven projects are both supported automatically.
Part 6: Common Configuration Mistakes
| Mistake | Symptom | Fix |
|---|---|---|
| Surefire plugin version < 3.0.0 | 0 tests run / engine error | Upgrade to 3.2.5+ |
Missing useJUnitPlatform() in Gradle | 0 tests run | Add it to the test block |
Test class is public but method is private | Test not discovered | Use package-private or public methods |
Using junit-vintage-engine without junit-jupiter | JUnit 4 tests run, JUnit 6 tests don’t | Add both engines if needed |
Dependency scope is compile instead of test | JUnit ends up in production JAR | Use scope=test / testImplementation |
Expected Console Output
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running com.example.CalculatorTest
[INFO] Tests run: 6, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.41 s
Results:
Tests run: 6, Failures: 0, Errors: 0, Skipped: 0
BUILD SUCCESS
Frequently Asked Questions (FAQs)
Q1: What is the difference between maven-surefire-plugin and maven-failsafe-plugin?
Surefire runs unit tests during the test phase and fails the build immediately if a test fails. Failsafe runs integration tests during the integration-test phase and defers build failure to the verify phase — this allows teardown steps (like stopping a test server) to run even if a test fails.
Q2: Why do I need useJUnitPlatform() in Gradle?
Without useJUnitPlatform(), Gradle uses its own legacy test discovery mechanism which does not know about JUnit Platform engines. This results in zero tests being discovered or run even though your test classes exist. This line activates the JUnit 6 engine for test discovery and execution.
Q3: Can I use both JUnit 4 and JUnit 6 tests in the same Maven project?
Yes. Add both junit-jupiter (for JUnit 6 tests) and junit-vintage-engine (to run old JUnit 4 tests on the JUnit Platform). Both will be discovered and run by Surefire automatically during the same build.
Q4: How do I generate an HTML test report with Maven?
Maven Surefire generates XML reports in target/surefire-reports/ automatically. To get an HTML report, run mvn surefire-report:report after your tests. The HTML report is generated in target/site/surefire-report.html. For richer reports, integrate Allure — covered in Test Reporting in JUnit 6.
Q5: How do I run JUnit 6 tests in a multi-module Gradle project?
Add a subprojects block in your root build.gradle to apply the JUnit 6 configuration to every submodule:
// root build.gradle
subprojects {
apply plugin: 'java'
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter:6.1.1'
}
test {
useJUnitPlatform()
}
}
See Also
- Getting Started with JUnit 6: Installation, Setup & First Test
- JUnit 6 Project Structure and Best Practices
- Tags and Test Suites in JUnit 6: Organizing Large Test Bases
- Running JUnit 6 Tests in CI/CD Pipelines (GitHub Actions, Jenkins)
- Code Coverage with JaCoCo and JUnit 6: Complete Setup
Conclusion
You now have a complete, production-ready JUnit 6 build configuration for both Maven and Gradle. You know how to separate unit tests from integration tests, filter by tag, handle multi-module projects, and avoid the most common setup mistakes.
Next: JUnit 6 Project Structure and Best Practices — learn how to organise your test source tree for long-term maintainability.