Managing JUnit Test Timeout
Long-running or infinite loops in unit tests can stall automated CI/CD build pipelines and waste compute resources. JUnit 5 offers multiple ways to enforce execution time limits, including assertTimeout, preemptive thread execution, and the declarative @Timeout annotation. In this guide, you will learn how to apply time limits at method, class, and global configuration levels.
Here is an example
package com.example;
import static org.junit.Assert.assertEquals;
import static java.time.Duration.ofMillis;
import static java.time.Duration.ofMinutes;
import static org.junit.jupiter.api.Assertions.assertTimeout;
import org.junit.jupiter.api.Test;
public class TimeAssertionOutExample {
private static String greeting() {
return "Hello";
}
// The following assertion succeeds.
@Test
void simpleTimeout() {
assertTimeout(ofMinutes(1), () -> {
// Perform task that takes less than 1 minute.
});
}
@Test
void simpleTimeoutWithResult() {
// The following assertion succeeds, and returns the supplied object.
String actualResult = assertTimeout(ofMinutes(1), () -> {
return "a result";
});
assertEquals("a result", actualResult);
}
// The following assertion invokes a method reference and returns an object.
@Test
void simpleTimeoutWithMethod() {
String actualGreeting = assertTimeout(ofMinutes(1), TimeAssertionOutExample::greeting);
assertEquals("Hello", actualGreeting);
}
// The following assertion fails with an error message similar to:
// execution exceeded timeout of 10 ms by 91 ms
@Test
void timeoutExceeded() {
assertTimeout(ofMillis(10), () -> {
Thread.sleep(100);
});
}
}
Include the following dependency to run the Testsuite class:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<junit-platform.version>1.2.0</junit-platform.version>
<junit-jupiter.version>5.2.0</junit-jupiter.version>
</properties>
<dependencies>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-runner</artifactId>
<version>${junit-platform.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit-jupiter.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>${junit-jupiter.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit-jupiter.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
Common Problems & Solutions
Problem: ThreadLocal context or security context is lost inside assertTimeoutPreemptively.
Cause: assertTimeoutPreemptively executes the test block in a separate worker thread to allow aborting hung execution, breaking thread-bound contexts.
Solution: Use standard assertTimeout (which runs in the same thread) or explicitly transfer ThreadLocal state into the execution closure.
Problem: Tests fail intermittently on slow CI servers due to strict timeout thresholds.
Cause: Hardcoded millisecond timeouts that pass locally fail under heavy CI CPU load.
Solution: Configure global default timeouts using junit-platform.properties or use environment-aware dynamic timeouts.
Recommended Articles
Unlock JUnit 5 Test Execution in Maven Projects - A Comprehensive Guide
Ensure your JUnit 5 tests run smoothly with this comprehensive guide to resolving common issues.
JUnit 5 Cheatsheet: Essential Tips for Java Developers
Master JUnit 5 Jupiter Tests with our comprehensive cheatsheet. Learn about lifecycle, assertions, and conditional execution in Java.
JUnit 5: Comprehensive Guide to Asserting Exceptions in Tests
Learn how to assert exceptions in JUnit 5 and JUnit4 tests with examples. #JUnit #JavaTesting #CloudNative
Mastering Test Tagging in JUnit 5: Filtering and Executing Tests with Ease
Learn how to tag tests in JUnit 5 using annotations like @Tag. Discover two ways to filter test execution: Maven-Surefire plugin configuration and custom TestSuite class usage.