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
@Testmethods junit.jupiter.execution.timeout.testtemplate.method.default-
Default timeout for
@TestTemplatemethods junit.jupiter.execution.timeout.testfactory.method.default-
Default timeout for
@TestFactorymethods junit.jupiter.execution.timeout.lifecycle.method.default-
Default timeout for all lifecycle methods
junit.jupiter.execution.timeout.beforeall.method.default-
Default timeout for
@BeforeAllmethods junit.jupiter.execution.timeout.beforeeach.method.default-
Default timeout for
@BeforeEachmethods junit.jupiter.execution.timeout.aftereach.method.default-
Default timeout for
@AfterEachmethods junit.jupiter.execution.timeout.afterall.method.default-
Default timeout for
@AfterAllmethods
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.
| Parameter value | Equivalent annotation |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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.