Timeouts

The @Timeout annotation allows one to declare that a test, test factory, test template, or lifecycle method should fail if its execution time exceeds a given duration. The time unit for the duration defaults to seconds but is configurable.

The following example shows how @Timeout is applied to lifecycle and test methods.

class TimeoutDemo {

	@BeforeEach
	@Timeout(5)
	void setUp() {
		// fails if execution time exceeds 5 seconds
	}

	@Test
	@Timeout(value = 500, unit = TimeUnit.MILLISECONDS)
	void failsIfExecutionTimeExceeds500Milliseconds() {
		// fails if execution time exceeds 500 milliseconds
	}

	@Test
	@Timeout(value = 500, unit = TimeUnit.MILLISECONDS, threadMode = ThreadMode.SEPARATE_THREAD)
	void failsIfExecutionTimeExceeds500MillisecondsInSeparateThread() {
		// fails if execution time exceeds 500 milliseconds, the test code is executed in a separate thread
	}

}

To apply the same timeout to all test methods within a test class and all of its @Nested classes, you can declare the @Timeout annotation at the class level. It will then be applied to all test, test factory, and test template methods within that class and its @Nested classes unless overridden by a @Timeout annotation on a specific method or @Nested class. Please note that @Timeout annotations declared at the class level are not applied to lifecycle methods.

Declaring @Timeout on a @TestFactory method checks that the factory method returns within the specified duration but does not verify the execution time of each individual DynamicTest generated by the factory. Please use assertTimeout() or assertTimeoutPreemptively() for that purpose.

If @Timeout is present on a @TestTemplate method — for example, a @RepeatedTest or @ParameterizedTest — each invocation will have the given timeout applied to it.

Thread mode

The timeout can be applied using one of the following three thread modes: SAME_THREAD, SEPARATE_THREAD, or INFERRED.

When SAME_THREAD is used, the execution of the annotated method proceeds in the main thread of the test. If the timeout is exceeded, the main thread is interrupted from another thread. This is done to ensure interoperability with frameworks such as Spring that make use of mechanisms that are sensitive to the currently running thread — for example, ThreadLocal transaction management.

On the contrary when SEPARATE_THREAD is used, like the assertTimeoutPreemptively() assertion, the execution of the annotated method proceeds in a separate thread, this can lead to undesirable side effects, see Preemptive Timeouts with assertTimeoutPreemptively().

When INFERRED (default) thread mode is used, the thread mode is resolved via the junit.jupiter.execution.timeout.thread.mode.default configuration parameter. If the provided configuration parameter is invalid or not present then SAME_THREAD is used as fallback.

Default Timeouts

The following configuration parameters can be used to specify default timeouts for all methods of a certain category unless they or an enclosing test class is annotated with @Timeout:

junit.jupiter.execution.timeout.default

Default timeout for all testable and lifecycle methods

junit.jupiter.execution.timeout.testable.method.default

Default timeout for all testable methods

junit.jupiter.execution.timeout.test.method.default

Default timeout for @Test methods

junit.jupiter.execution.timeout.testtemplate.method.default

Default timeout for @TestTemplate methods

junit.jupiter.execution.timeout.testfactory.method.default

Default timeout for @TestFactory methods

junit.jupiter.execution.timeout.lifecycle.method.default

Default timeout for all lifecycle methods

junit.jupiter.execution.timeout.beforeall.method.default

Default timeout for @BeforeAll methods

junit.jupiter.execution.timeout.beforeeach.method.default

Default timeout for @BeforeEach methods

junit.jupiter.execution.timeout.aftereach.method.default

Default timeout for @AfterEach methods

junit.jupiter.execution.timeout.afterall.method.default

Default timeout for @AfterAll methods

More specific configuration parameters override less specific ones. For example, junit.jupiter.execution.timeout.test.method.default overrides junit.jupiter.execution.timeout.testable.method.default which overrides junit.jupiter.execution.timeout.default.

The values of such configuration parameters must be in the following, case-insensitive format: <number> [ns|μs|ms|s|m|h|d]. The space between the number and the unit may be omitted. Specifying no unit is equivalent to using seconds.

Example timeout configuration parameter values
Parameter value Equivalent annotation

42

@Timeout(42)

42 ns

@Timeout(value = 42, unit = NANOSECONDS)

42 μs

@Timeout(value = 42, unit = MICROSECONDS)

42 ms

@Timeout(value = 42, unit = MILLISECONDS)

42 s

@Timeout(value = 42, unit = SECONDS)

42 m

@Timeout(value = 42, unit = MINUTES)

42 h

@Timeout(value = 42, unit = HOURS)

42 d

@Timeout(value = 42, unit = DAYS)

Using @Timeout for Polling Tests

When dealing with asynchronous code, it is common to write tests that poll while waiting for something to happen before performing any assertions. In some cases you can rewrite the logic to use a CountDownLatch or another synchronization mechanism, but sometimes that is not possible — for example, if the subject under test sends a message to a channel in an external message broker and assertions cannot be performed until the message has been successfully sent through the channel. Asynchronous tests like these require some form of timeout to ensure they don’t hang the test suite by executing indefinitely, as would be the case if an asynchronous message never gets successfully delivered.

By configuring a timeout for an asynchronous test that polls, you can ensure that the test does not execute indefinitely. The following example demonstrates how to achieve this with JUnit Jupiter’s @Timeout annotation. This technique can be used to implement "poll until" logic very easily.

@Test
@Timeout(5) // Poll at most 5 seconds
void pollUntil() throws InterruptedException {
	while (asynchronousResultNotAvailable()) {
		Thread.sleep(250); // custom poll interval
	}
	// Obtain the asynchronous result and perform assertions
}
If you need more control over polling intervals and greater flexibility with asynchronous tests, consider using a dedicated library such as Awaitility.

Debugging Timeouts

Registered Pre-Interrupt Callback extensions are called prior to invoking Thread.interrupt() on the thread that is executing the timed out method. This allows to inspect the application state and output additional information that might be helpful for diagnosing the cause of a timeout.

Thread Dump on Timeout

JUnit registers a default implementation of the Pre-Interrupt Callback extension point that dumps the stacks of all threads to System.out if enabled by setting the junit.jupiter.execution.timeout.threaddump.enabled configuration parameter to true.

Disable @Timeout Globally

When stepping through your code in a debug session, a fixed timeout limit may influence the result of the test, e.g. mark the test as failed although all assertions were met.

JUnit Jupiter supports the junit.jupiter.execution.timeout.mode configuration parameter to configure when timeouts are applied. There are three modes: enabled, disabled, and disabled_on_debug. The default mode is enabled. A VM runtime is considered to run in debug mode when one of its input parameters starts with -agentlib:jdwp or -Xrunjdwp. This heuristic is queried by the disabled_on_debug mode.