How do I configure Gradle to run JUnit tests?

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:

  1. Add the JUnit Jupiter dependency to testImplementation.
  2. Enable the JUnit Platform in the test task with useJUnitPlatform().

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/java into production classes.
  • Compiles src/test/java into test classes.
  • Runs everything under src/test/java when you execute the test task.

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:

  1. Apply the java plugin.
  2. Add junit-jupiter to testImplementation.
  3. Call useJUnitPlatform() in the test task.
  4. (Optional) Configure logging, tags, parallelism, and reports.
  5. (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.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.