2.18. Timeouts
Declarative timeouts are an experimental feature You’re invited to give it a try and provide feedback to the JUnit team so they can improve and eventually promote this feature. |
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 = 100, unit = TimeUnit.MILLISECONDS)
void failsIfExecutionTimeExceeds100Milliseconds() {
// fails if execution time exceeds 100 milliseconds
}
}
Contrary to the assertTimeoutPreemptively()
assertion, 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.
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.
The following configuration parameters can be used to specify global 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.
Parameter value | Equivalent annotation |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2.18.1. 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. |
2.18.2. 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
. This heuristic is queried by the disabled_on_debug
mode.