Gradle has excellent built-in support for running JUnit tests. Configuring it properly ensures your tests are discovered, executed, and reported correctly. Let’s walk through the setup step by step.
The Short Answer
To run JUnit 5 (Jupiter) tests with Gradle, you need to:
- Add the JUnit Jupiter dependency to
testImplementation. - Enable the JUnit Platform in the
testtask withuseJUnitPlatform().
Minimal Groovy DSL example:
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter:5.13.4'
}
test {
useJUnitPlatform()
}
That’s it — Gradle will now discover and run all JUnit 5 tests in src/test/java.
1. Understand the Standard Project Layout
Gradle follows a conventional directory layout:
my-project/
├── build.gradle
├── src/
│ ├── main/
│ │ └── java/
│ │ └── com/example/Calculator.java
│ └── test/
│ └── java/
│ └── com/example/CalculatorTest.java
Gradle automatically:
- Compiles
src/main/javainto production classes. - Compiles
src/test/javainto test classes. - Runs everything under
src/test/javawhen you execute thetesttask.
You do not need to tell Gradle where the tests are, as long as you follow this layout.
2. Apply the Java Plugin
The Java plugin provides the test task and the testImplementation configuration.
plugins {
id 'java'
}
For a Kotlin DSL (build.gradle.kts) project:
plugins {
java
}
3. Add JUnit 5 Dependencies
For a modern JUnit 5 (Jupiter) setup:
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter:5.13.4'
}
The junit-jupiter aggregate dependency brings in both:
- junit-jupiter-api — the annotations and assertions you write with (
@Test,assertEquals, etc.). - junit-jupiter-engine — the engine that actually runs your Jupiter tests.
If you also need to run older JUnit 4 tests, add the Vintage engine:
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter:5.13.4'
testRuntimeOnly 'org.junit.vintage:junit-vintage-engine:5.13.4'
}
4. Enable the JUnit Platform
By default, Gradle uses the older JUnit 4 test runner. You must explicitly enable the JUnit Platform for JUnit 5:
test {
useJUnitPlatform()
}
Kotlin DSL equivalent:
tasks.test {
useJUnitPlatform()
}
Without this line, JUnit 5 tests will simply not run — a very common gotcha.
5. A Complete Minimal build.gradle
plugins {
id 'java'
}
group = 'com.example'
version = '1.0.0'
repositories {
mavenCentral()
}
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter:5.13.4'
}
test {
useJUnitPlatform()
}
Run tests from the command line:
./gradlew test
6. Using the Kotlin DSL (build.gradle.kts)
If you prefer Kotlin DSL:
plugins {
java
}
group = "com.example"
version = "1.0.0"
repositories {
mavenCentral()
}
dependencies {
testImplementation("org.junit.jupiter:junit-jupiter:5.13.4")
}
tasks.test {
useJUnitPlatform()
}
7. Filtering Tests by Tags
If you use @Tag on your tests, you can include or exclude them:
test {
useJUnitPlatform {
includeTags 'fast'
excludeTags 'slow', 'integration'
}
}
Kotlin DSL:
tasks.test {
useJUnitPlatform {
includeTags("fast")
excludeTags("slow", "integration")
}
}
This is invaluable for separating unit tests from slower integration tests.
8. Improve Test Logging
By default, Gradle prints only a short summary. You will often want more detail:
test {
useJUnitPlatform()
testLogging {
events "passed", "failed", "skipped"
showStandardStreams = true
exceptionFormat = "full"
}
}
This makes failures much easier to diagnose.
9. Configure Parallel Execution (Optional)
You can allow Gradle to run tests in parallel across multiple JVM forks:
test {
useJUnitPlatform()
maxParallelForks = Runtime.runtime.availableProcessors().intdiv(2) ?: 1
}
Each fork runs in a separate JVM, which increases speed but also memory usage.
10. Set JVM Options and System Properties
Sometimes tests need specific JVM arguments or system properties:
test {
useJUnitPlatform()
jvmArgs '-Xmx1g', '-XX:+UseG1GC'
systemProperty 'user.timezone', 'UTC'
systemProperty 'file.encoding', 'UTC-8'
}
11. Enable Test Reports
Gradle generates HTML and XML test reports automatically:
build/reports/tests/test/index.html ← Human-readable HTML report
build/test-results/test/*.xml ← Machine-readable XML report
You can customize them:
test {
useJUnitPlatform()
reports {
html.required = true
junitXml.required = true
}
}
The XML reports are what CI servers (Jenkins, GitHub Actions, etc.) consume.
12. Separate Integration Tests (Advanced)
For larger projects, you often want to separate unit tests from integration tests. A clean way to do this is with a dedicated source set and task:
sourceSets {
integrationTest {
java.srcDir 'src/integrationTest/java'
resources.srcDir 'src/integrationTest/resources'
compileClasspath += sourceSets.main.output + configurations.testRuntimeClasspath
runtimeClasspath += output + compileClasspath
}
}
tasks.register('integrationTest', Test) {
description = 'Runs integration tests.'
group = 'verification'
testClassesDirs = sourceSets.integrationTest.output.classesDirs
classpath = sourceSets.integrationTest.runtimeClasspath
useJUnitPlatform()
shouldRunAfter test
}
check.dependsOn integrationTest
Now:
./gradlew test # Runs unit tests only
./gradlew integrationTest # Runs integration tests only
./gradlew check # Runs everything
13. Running Tests from the Command Line
Gradle supports many useful test-running options out of the box:
# Run all tests
./gradlew test
# Run tests in one class
./gradlew test --tests "com.example.CalculatorTest"
# Run a single test method
./gradlew test --tests "com.example.CalculatorTest.addsTwoNumbers"
# Run tests matching a pattern
./gradlew test --tests "*Calculator*"
# Continuous mode — rerun tests when files change
./gradlew test --continuous
# Skip tests entirely (not recommended)
./gradlew build -x test
14. Common Pitfalls
| Problem | Cause | Fix |
|---|---|---|
| Tests are compiled but not run | Missing useJUnitPlatform() |
Add it to the test block |
@Test not recognized |
JUnit 4 imports used | Use org.junit.jupiter.api.Test |
| Tests run twice | Both Jupiter and Vintage engines present unintentionally | Remove Vintage if you don’t need it |
NoClassDefFoundError for engines |
Only added junit-jupiter-api |
Use the aggregate junit-jupiter or add junit-jupiter-engine |
| Tests not found | Files outside src/test/java |
Move them or add a custom source set |
15. Verifying Your Setup
Create a simple test to confirm everything works:
package com.example;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
class SanityCheckTest {
@Test
void oneEqualsOne() {
assertEquals(1, 1);
}
}
Run:
./gradlew test
You should see:
BUILD SUCCESSFUL
And a report at build/reports/tests/test/index.html.
Final Summary
To configure Gradle to run JUnit tests:
- Apply the
javaplugin. - Add
junit-jupitertotestImplementation. - Call
useJUnitPlatform()in thetesttask. - (Optional) Configure logging, tags, parallelism, and reports.
- (Optional) Add the Vintage engine if you still have JUnit 4 tests.
A modern, well-configured build.gradle for JUnit 5 looks like this:
plugins {
id 'java'
}
repositories {
mavenCentral()
}
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter:5.13.4'
}
test {
useJUnitPlatform()
testLogging {
events "passed", "failed", "skipped"
exceptionFormat = "full"
}
}
With that in place, ./gradlew test will discover, run, and report on your JUnit tests — everything you need for a clean, reliable testing workflow.
