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
, Collection
, Iterable
, Iterator
, or array of DynamicNode
instances. 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 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.
As of JUnit Jupiter 5.7.0, dynamic tests must always be created by factory methods; however, this might be complemented by a registration facility in a later release.
2.17.1. Dynamic Test Examples
The following DynamicTestsDemo
class demonstrates several examples of test factories and dynamic tests.
The next five methods are very simple examples that demonstrate the generation of a Collection
, Iterable
, Iterator
, 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 easy it is 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 method generates a single DynamicTest
instead of a stream, and the dynamicNodeSingleContainer()
method generates a nested hierarchy of dynamic tests utilizing DynamicContainer
.
2.17.2. 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
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.selectMethod(String)
for the supported formats for a FQMN.
UriSource