Skip to content

Commit f78e9cc

Browse files
committed
Document declarative timeouts in User Guide
1 parent c6f9861 commit f78e9cc

File tree

5 files changed

+158
-14
lines changed

5 files changed

+158
-14
lines changed

documentation/src/docs/asciidoc/release-notes/release-notes-5.5.0-M2.adoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ on GitHub.
5151

5252
==== New Features and Improvements
5353

54+
* Support for declarative timeouts using `@Timeout` or configuration parameters (see
55+
<<../user-guide/index.adoc#writing-tests-declarative-timeouts, User Guide>> for details)
5456
* New overloaded variants of `Assertions.assertLinesMatch(...)` that accept a `String` or
5557
a `Supplier<String>` for a custom failure message.
5658
* Failure messages for `Assertions.assertLinesMatch(...)` now emit each expected and

documentation/src/docs/asciidoc/user-guide/writing-tests.adoc

Lines changed: 95 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ in the `junit-jupiter-api` module.
4040
| `@Nested` | Denotes that the annotated class is a non-static <<writing-tests-nested,nested test class>>. `@BeforeAll` and `@AfterAll` methods cannot be used directly in a `@Nested` test class unless the "per-class" <<writing-tests-test-instance-lifecycle, test instance lifecycle>> is used. Such annotations are not _inherited_.
4141
| `@Tag` | Used to declare <<writing-tests-tagging-and-filtering,tags for filtering tests>>, either at the class or method level; analogous to test groups in TestNG or Categories in JUnit 4. Such annotations are _inherited_ at the class level but not at the method level.
4242
| `@Disabled` | Used to <<writing-tests-disabling,disable>> a test class or test method; analogous to JUnit 4's `@Ignore`. Such annotations are not _inherited_.
43+
| `@Timeout` | Used to fail a test, test factory, test template, or lifecycle method if its execution exceeds a given duration. Such annotations are _inherited_.
4344
| `@ExtendWith` | Used to <<extensions-registration-declarative,register extensions declaratively>>. Such annotations are _inherited_.
4445
| `@RegisterExtension` | Used to <<extensions-registration-programmatic,register extensions programmatically>> via fields. Such fields are _inherited_ unless they are _shadowed_.
4546
| `@TempDir` | Used to supply a <<writing-tests-built-in-extensions-TempDirectory,temporary directory>> via field injection or parameter injection in a lifecycle method or test method; located in the `org.junit.jupiter.api.io` package.
@@ -217,11 +218,12 @@ include::{testDir}/example/AssertionsDemo.java[tags=user_guide]
217218

218219
[[writing-tests-assertions-preemptive-timeouts]]
219220
[WARNING]
220-
.Preemptive Timeouts
221+
.Preemptive Timeouts with `assertTimeoutPreemptively()`
221222
====
222-
The various `assertTimeoutPreemptively()` methods in the `Assertions` class execute the
223-
provided `executable` or `supplier` in a different thread than that of the calling code.
224-
This behavior can lead to undesirable side effects if the code that is executed within the
223+
Contrary to <<writing-tests-declarative-timeouts, declarative timeouts>>, the various
224+
`assertTimeoutPreemptively()` methods in the `Assertions` class execute the provided
225+
`executable` or `supplier` in a different thread than that of the calling code. This
226+
behavior can lead to undesirable side effects if the code that is executed within the
225227
`executable` or `supplier` relies on `java.lang.ThreadLocal` storage.
226228
227229
One common example of this is the transactional testing support in the Spring Framework.
@@ -1570,6 +1572,95 @@ include::{testDir}/example/DynamicTestsDemo.java[tags=user_guide]
15701572
----
15711573

15721574

1575+
[[writing-tests-declarative-timeouts]]
1576+
=== Timeouts
1577+
1578+
.Declarative timeouts are an experimental feature
1579+
WARNING: You're invited to give it a try and provide feedback to the JUnit team so they
1580+
can improve and eventually <<api-evolution, promote>> this feature.
1581+
1582+
The `@Timeout` annotation allows to declare that a test, test factory, test template, or
1583+
lifecycle method should fail if its execution time exceeds a given duration, and
1584+
optionally a time unit (seconds are used by default).
1585+
1586+
The following example shows how `@Timeout` is applied to lifecycle and test methods.
1587+
1588+
[source,java]
1589+
----
1590+
include::{testDir}/example/TimeoutDemo.java[tags=user_guide]
1591+
----
1592+
1593+
Contrary to the `assertTimeoutPreemptively()` assertion, the execution of the annotated
1594+
method proceeds in the main thread of the test. If the timeout is exceeded, the main
1595+
thread is interrupted from another thread. This is done to ensure interoperability with
1596+
frameworks such as Spring that make extensive use of mechanisms that are sensitive to the
1597+
currently running thread (e.g. `ThreadLocals`).
1598+
1599+
To apply the same timeout to all test methods within a test class and all its `@Nested`
1600+
classes, you can declare the `@Timeout` annotation on the class level. It will then be
1601+
applied to all test, test factory, and test template methods within that class and its
1602+
`@Nested` classes unless overridden by a `@Timeout` annotation on a method or `@Nested`
1603+
class. Please note that `@Timeout` annotations declared on the class level are not
1604+
applied to lifecycle methods.
1605+
1606+
Declaring `@Timeout` on a test factory method checks that the method returns within the
1607+
specified duration but does verify the execution time of the returned `DynamicTests`.
1608+
Please use `assertTimeout()`/`assertTimeoutPreemptively()` for that purpose.
1609+
1610+
If `@Timeout` is present on a test template method, such as a method annotated with
1611+
`@RepeatedTest` or `@ParameterizedTest`, each invocation is checked to finish within the
1612+
given timeout.
1613+
1614+
The following <<running-tests-config-params, configuration parameters>> can be used to
1615+
specify global timeouts for all methods of a certain category unless they or an enclosing
1616+
test class is annotated with `@Timeout`:
1617+
1618+
`junit.jupiter.execution.timeout.default`::
1619+
Default timeout for all testable and lifecycle methods
1620+
`junit.jupiter.execution.timeout.testable.method.default`::
1621+
Default timeout for all testable methods
1622+
`junit.jupiter.execution.timeout.test.method.default`::
1623+
Default timeout for `@Test` methods
1624+
`junit.jupiter.execution.timeout.testtemplate.method.default`::
1625+
Default timeout for `@TestTemplate` methods
1626+
`junit.jupiter.execution.timeout.testfactory.method.default`::
1627+
Default timeout for `@TestFactory` methods
1628+
`junit.jupiter.execution.timeout.lifecycle.method.default`::
1629+
Default timeout for all lifecycle methods
1630+
`junit.jupiter.execution.timeout.beforeall.method.default`::
1631+
Default timeout for `@BeforeAll` methods
1632+
`junit.jupiter.execution.timeout.beforeeach.method.default`::
1633+
Default timeout for `@BeforeEach` methods
1634+
`junit.jupiter.execution.timeout.aftereach.method.default`::
1635+
Default timeout for `@AfterEach` methods
1636+
`junit.jupiter.execution.timeout.afterall.method.default`::
1637+
Default timeout for `@AfterAll` methods
1638+
1639+
More specific configuration parameters override less specific ones. For example,
1640+
`junit.jupiter.execution.timeout.test.method.default` overrides
1641+
`junit.jupiter.execution.timeout.testable.method.default` which overrides
1642+
`junit.jupiter.execution.timeout.default`.
1643+
1644+
The values of such configuration parameters must be in the following, case-insensitive
1645+
format: `<number> [ns|μs|ms|s|m|h|d]`. The space between the number and the unit may be
1646+
omitted. Specifying no unit is equivalent to using seconds.
1647+
1648+
.Example timeout configuration parameter values
1649+
[cols="20,80"]
1650+
|===
1651+
| Parameter value | Equivalent annotation
1652+
1653+
| `42` | `@Timeout(42)`
1654+
| `42 ns` | `@Timeout(value = 42, unit = NANOSECONDS)`
1655+
| `42 μs` | `@Timeout(value = 42, unit = MICROSECONDS)`
1656+
| `42 ms` | `@Timeout(value = 42, unit = MILLISECONDS)`
1657+
| `42 s` | `@Timeout(value = 42, unit = SECONDS)`
1658+
| `42 m` | `@Timeout(value = 42, unit = MINUTES)`
1659+
| `42 h` | `@Timeout(value = 42, unit = HOURS)`
1660+
| `42 d` | `@Timeout(value = 42, unit = DAYS)`
1661+
|===
1662+
1663+
15731664
[[writing-tests-parallel-execution]]
15741665
=== Parallel Execution
15751666

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright 2015-2019 the original author or authors.
3+
*
4+
* All rights reserved. This program and the accompanying materials are
5+
* made available under the terms of the Eclipse Public License v2.0 which
6+
* accompanies this distribution and is available at
7+
*
8+
* https://www.eclipse.org/legal/epl-v20.html
9+
*/
10+
11+
package example;
12+
13+
import java.util.concurrent.TimeUnit;
14+
15+
import org.junit.jupiter.api.BeforeEach;
16+
import org.junit.jupiter.api.Test;
17+
import org.junit.jupiter.api.Timeout;
18+
19+
// tag::user_guide[]
20+
class TimeoutDemo {
21+
22+
@BeforeEach
23+
@Timeout(5)
24+
void setUp() {
25+
// fails if execution time exceeds 5 seconds
26+
}
27+
28+
@Test
29+
@Timeout(value = 100, unit = TimeUnit.MILLISECONDS)
30+
void failsIfExecutionTimeExceedsFiveSeconds() {
31+
// fails if execution time exceeds 100 milliseconds
32+
}
33+
34+
}
35+
// end::user_guide[]

junit-jupiter-api/src/main/java/org/junit/jupiter/api/Timeout.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,22 @@
6868
* overrides {@code junit.jupiter.execution.timeout.testable.method.default}
6969
* which overrides {@code junit.jupiter.execution.timeout.default}.
7070
*
71+
* <p>Values must be in the following, case-insensitive format:
72+
* {@code <number> [ns|μs|ms|s|m|h|d]}. The space between the number and the
73+
* unit may be omitted. Specifying no unit is equivalent to using seconds.
74+
*
75+
* <table class="plain">
76+
* <tr><th> Value </th><th> Equivalent annotation </th></tr>
77+
* <tr><td> {@code 42} </td><td> {@code @Timeout(42)} </td></tr>
78+
* <tr><td> {@code 42 ns} </td><td> {@code @Timeout(value = 42, unit = NANOSECONDS)} </td></tr>
79+
* <tr><td> {@code 42 μs} </td><td> {@code @Timeout(value = 42, unit = MICROSECONDS)} </td></tr>
80+
* <tr><td> {@code 42 ms} </td><td> {@code @Timeout(value = 42, unit = MILLISECONDS)} </td></tr>
81+
* <tr><td> {@code 42 s} </td><td> {@code @Timeout(value = 42, unit = SECONDS)} </td></tr>
82+
* <tr><td> {@code 42 m} </td><td> {@code @Timeout(value = 42, unit = MINUTES)} </td></tr>
83+
* <tr><td> {@code 42 h} </td><td> {@code @Timeout(value = 42, unit = HOURS)} </td></tr>
84+
* <tr><td> {@code 42 d} </td><td> {@code @Timeout(value = 42, unit = DAYS)} </td></tr>
85+
* </table>
86+
*
7187
* @since 5.5
7288
*/
7389
@Target({ ElementType.TYPE, ElementType.METHOD })

junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/Constants.java

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ public final class Constants {
198198
*
199199
* <h3>Supported Values</h3>
200200
*
201-
* <p>Value must be in the following, case-insensitive format:
201+
* <p>Values must be in the following, case-insensitive format:
202202
* {@code <number> [ns|μs|ms|s|m|h|d]}. The space between the number and the
203203
* unit may be omitted. Specifying no unit is equivalent to using seconds.
204204
*
@@ -232,7 +232,7 @@ public final class Constants {
232232
*
233233
* <h3>Supported Values</h3>
234234
*
235-
* <p>Value must be in the following, case-insensitive format:
235+
* <p>Values must be in the following, case-insensitive format:
236236
* {@code <number> [ns|μs|ms|s|m|h|d]}. The space between the number and the
237237
* unit may be omitted. Specifying no unit is equivalent to using seconds.
238238
*
@@ -268,7 +268,7 @@ public final class Constants {
268268
*
269269
* <h3>Supported Values</h3>
270270
*
271-
* <p>Value must be in the following, case-insensitive format:
271+
* <p>Values must be in the following, case-insensitive format:
272272
* {@code <number> [ns|μs|ms|s|m|h|d]}. The space between the number and the
273273
* unit may be omitted. Specifying no unit is equivalent to using seconds.
274274
*
@@ -304,7 +304,7 @@ public final class Constants {
304304
*
305305
* <h3>Supported Values</h3>
306306
*
307-
* <p>Value must be in the following, case-insensitive format:
307+
* <p>Values must be in the following, case-insensitive format:
308308
* {@code <number> [ns|μs|ms|s|m|h|d]}. The space between the number and the
309309
* unit may be omitted. Specifying no unit is equivalent to using seconds.
310310
*
@@ -340,7 +340,7 @@ public final class Constants {
340340
*
341341
* <h3>Supported Values</h3>
342342
*
343-
* <p>Value must be in the following, case-insensitive format:
343+
* <p>Values must be in the following, case-insensitive format:
344344
* {@code <number> [ns|μs|ms|s|m|h|d]}. The space between the number and the
345345
* unit may be omitted. Specifying no unit is equivalent to using seconds.
346346
*
@@ -374,7 +374,7 @@ public final class Constants {
374374
*
375375
* <h3>Supported Values</h3>
376376
*
377-
* <p>Value must be in the following, case-insensitive format:
377+
* <p>Values must be in the following, case-insensitive format:
378378
* {@code <number> [ns|μs|ms|s|m|h|d]}. The space between the number and the
379379
* unit may be omitted. Specifying no unit is equivalent to using seconds.
380380
*
@@ -409,7 +409,7 @@ public final class Constants {
409409
*
410410
* <h3>Supported Values</h3>
411411
*
412-
* <p>Value must be in the following, case-insensitive format:
412+
* <p>Values must be in the following, case-insensitive format:
413413
* {@code <number> [ns|μs|ms|s|m|h|d]}. The space between the number and the
414414
* unit may be omitted. Specifying no unit is equivalent to using seconds.
415415
*
@@ -444,7 +444,7 @@ public final class Constants {
444444
*
445445
* <h3>Supported Values</h3>
446446
*
447-
* <p>Value must be in the following, case-insensitive format:
447+
* <p>Values must be in the following, case-insensitive format:
448448
* {@code <number> [ns|μs|ms|s|m|h|d]}. The space between the number and the
449449
* unit may be omitted. Specifying no unit is equivalent to using seconds.
450450
*
@@ -479,7 +479,7 @@ public final class Constants {
479479
*
480480
* <h3>Supported Values</h3>
481481
*
482-
* <p>Value must be in the following, case-insensitive format:
482+
* <p>Values must be in the following, case-insensitive format:
483483
* {@code <number> [ns|μs|ms|s|m|h|d]}. The space between the number and the
484484
* unit may be omitted. Specifying no unit is equivalent to using seconds.
485485
*
@@ -514,7 +514,7 @@ public final class Constants {
514514
*
515515
* <h3>Supported Values</h3>
516516
*
517-
* <p>Value must be in the following, case-insensitive format:
517+
* <p>Values must be in the following, case-insensitive format:
518518
* {@code <number> [ns|μs|ms|s|m|h|d]}. The space between the number and the
519519
* unit may be omitted. Specifying no unit is equivalent to using seconds.
520520
*

0 commit comments

Comments
 (0)