= Dynamic Tests

The standard `@Test` annotation in JUnit Jupiter described in
xref:writing-tests/annotations.adoc[] is very similar to the `@Test` annotation in JUnit 4. Both
describe methods that implement test cases. These test cases are static in the sense that
they are fully specified at compile time, and their behavior cannot be changed by
anything happening at runtime. _Assumptions provide a basic form of dynamic behavior but
are intentionally rather limited in their expressiveness._

In addition to these standard tests a completely new kind of test programming model has
been introduced in JUnit Jupiter. This new kind of test is a _dynamic test_ which is
generated at runtime by a factory method that is annotated with `@TestFactory`.

In contrast to `@Test` methods, a `@TestFactory` method is not itself a test case but
rather a factory for test cases. Thus, a dynamic test is the product of a factory.
Technically speaking, a `@TestFactory` method must return a single `DynamicNode` or a
_stream_ of `DynamicNode` instances or any of its subclasses. In this context, a "stream"
is anything that JUnit can reliably convert into a `Stream`, such as `Stream`,
`Collection`, `Iterator`, `Iterable`, an array of objects, or any type that provides an
`iterator(): Iterator` method (such as, for example, a `kotlin.sequences.Sequence`).

Instantiable subclasses of `DynamicNode` are `DynamicContainer` and `DynamicTest`.
`DynamicContainer` instances are composed of a _display name_ and a list of dynamic child
nodes, enabling the creation of arbitrarily nested hierarchies of dynamic nodes.
`DynamicTest` instances will be executed lazily, enabling dynamic and even
non-deterministic generation of test cases.

Any `Stream` returned by a `@TestFactory` will be properly closed by calling
`stream.close()`, making it safe to use a resource such as `Files.lines()`.

As with `@Test` methods, `@TestFactory` methods must not be `private` or `static` and may
optionally declare parameters to be resolved by `ParameterResolvers`.

A `DynamicTest` is a test case generated at runtime. It is composed of a _display name_
and an `Executable`. `Executable` is a `@FunctionalInterface` which means that the
implementations of dynamic tests can be provided as _lambda expressions_ or _method
references_.

.Dynamic Test Lifecycle
WARNING: The execution lifecycle of a dynamic test is quite different than it is for a
standard `@Test` case. Specifically, there are no lifecycle callbacks for individual
dynamic tests. This means that `@BeforeEach` and `@AfterEach` methods and their
corresponding extension callbacks are executed for the `@TestFactory` method but not for
each _dynamic test_. In other words, if you access fields from the test instance within a
lambda expression for a dynamic test, those fields will not be reset by callback methods
or extensions between the execution of individual dynamic tests generated by the same
`@TestFactory` method.

[[examples]]
== Dynamic Test Examples

The following `DynamicTestsDemo` class demonstrates several examples of test factories
and dynamic tests.

The first method returns an invalid return type and will cause a warning to be reported by
JUnit during test discovery. Such methods are not executed.

The next six methods demonstrate the generation of a `Collection`, `Iterable`, `Iterator`,
array, or `Stream` of `DynamicTest` instances. Most of these examples do not really
exhibit dynamic behavior but merely demonstrate the supported return types in principle.
However, `dynamicTestsFromStream()` and `dynamicTestsFromIntStream()` demonstrate how to
generate dynamic tests for a given set of strings or a range of input numbers.

The next method is truly dynamic in nature. `generateRandomNumberOfTests()` implements an
`Iterator` that generates random numbers, a display name generator, and a test executor
and then provides all three to `DynamicTest.stream()`. Although the non-deterministic
behavior of `generateRandomNumberOfTests()` is of course in conflict with test
repeatability and should thus be used with care, it serves to demonstrate the
expressiveness and power of dynamic tests.

The next method is similar to `generateRandomNumberOfTests()` in terms of flexibility;
however, `dynamicTestsFromStreamFactoryMethod()` generates a stream of dynamic tests from
an existing `Stream` via the `DynamicTest.stream()` factory method.

For demonstration purposes, the `dynamicNodeSingleTest()` method generates a single
`DynamicTest` instead of a stream, and the `dynamicNodeSingleContainer()` method generates
a nested hierarchy of dynamic tests utilizing `DynamicContainer`.

[tabs]
====
Java::
+
--
[source,java,indent=0]
----
include::example$java/example/DynamicTestsDemo.java[tags=user_guide]
----
--

Kotlin::
+
--
[source,kotlin,indent=0]
----
include::example$kotlin/example/kotlin/DynamicTestsDemo.kt[tags=user_guide]
----
--
====

[[named-support]]
== Dynamic Tests and Named

In some cases, it can be more natural to specify inputs together with a descriptive name
using the {Named} API and the corresponding `stream()` factory methods on `DynamicTest` as
shown in the first example below. The second example takes it one step further and allows
to provide the code block that should be executed by implementing the `Executable`
interface along with `Named` via the `NamedExecutable` base class.

[tabs]
====
Java::
+
--
[source,java,indent=0]
----
include::example$java/example/DynamicTestsNamedDemo.java[tags=user_guide]
----
--

Kotlin::
+
--
[source,kotlin,indent=0]
----
include::example$kotlin/example/kotlin/DynamicTestsNamedDemo.kt[tags=user_guide]
----
--
====

[[uri-test-source]]
== URI Test Sources for Dynamic Tests

The JUnit Platform provides `TestSource`, a representation of the source of a test or
container used to navigate to its location by IDEs and build tools.

The `TestSource` for a dynamic test or dynamic container can be constructed from a
`java.net.URI` which can be supplied via the `DynamicTest.dynamicTest(String, URI,
Executable)` or `DynamicContainer.dynamicContainer(String, URI, Stream)` factory method,
respectively. The `URI` will be converted to one of the following `TestSource`
implementations.

`ClasspathResourceSource` ::
  If the `URI` contains the `classpath` scheme -- for example,
  `classpath:/test/foo.xml?line=20,column=2`.

`DirectorySource` ::
  If the `URI` represents a directory present in the file system.

`FileSource` ::
  If the `URI` represents a file present in the file system.

`MethodSource` ::
  If the `URI` contains the `method` scheme and the fully qualified method name (FQMN) --
  for example, `method:org.junit.Foo#bar(java.lang.String, java.lang.String[])`. Please
  refer to the Javadoc for `{DiscoverySelectors}.{DiscoverySelectors_selectMethod}` for the
  supported formats for a FQMN.

`ClassSource` ::
  If the `URI` contains the `class` scheme and the fully qualified class name --
  for example, `class:org.junit.Foo?line=42`.

`UriSource` ::
  If none of the above `TestSource` implementations are applicable.

[[parallel-execution]]
== Parallel Execution

Dynamic tests and containers support
xref:writing-tests/parallel-execution.adoc[parallel execution]. You can configure their
`ExecutionMode` by using the `dynamicTest(Consumer)` and `dynamicContainer(Consumer)`
factory methods as illustrated by the following example.

[tabs]
====
Java::
+
--
[source,java,indent=0]
----
include::example$java/example/DynamicTestsDemo.java[tags=execution_mode]
----
--

Kotlin::
+
--
[source,kotlin,indent=0]
----
include::example$kotlin/example/kotlin/DynamicTestsDemo.kt[tags=execution_mode]
----
--
====

Executing the above test factory method results in the following test tree and execution
modes:

* dynamicTestsWithConfiguredExecutionMode() -- `CONCURRENT` (from `@Execution` annotation)
** Container A -- `CONCURRENT` (from `@Execution` annotation)
*** not null -- `SAME_THREAD` (from `executionMode(...)` call)
*** properties -- `CONCURRENT` (from `@Execution` annotation)
**** length > 0 -- `CONCURRENT` (from `executionMode(...)` call)
**** not empty -- `SAME_THREAD` (from `childExecutionMode(...)` call)
** ... (same for "Container B" and "Container C")
