1. Overview
The goal of this document is to provide comprehensive reference documentation for both programmers writing tests and extension authors.
Work in progress! |
1.1. Supported Java Versions
JUnit 5 only supports Java 8 and above. However, you can still test classes compiled with lower versions.
2. Installation
Snapshot artifacts are deployed to Sonatype’s snapshots repository.
2.1. Dependency Metadata
-
Group ID:
org.junit
-
Version:
5.0.0-SNAPSHOT
-
Artifact IDs:
-
junit-commons
-
junit-console
-
junit-engine-api
-
junit-gradle
-
junit-launcher
-
junit4-engine
-
junit4-runner
-
junit5-api
-
junit5-engine
-
surefire-junit5
-
2.2. JUnit 5 Sample Projects
The junit5-samples
repository hosts a collection of sample
projects based on JUnit 5. You’ll find the respective build.gradle
and pom.xml
in
the projects below.
-
For Gradle, check out the
junit5-gradle-consumer
project. -
For Maven, check out the
junit5-maven-consumer
project.
3. Writing Tests
import static org.junit.gen5.api.Assertions.assertEquals;
import org.junit.gen5.api.Test;
class FirstJUnit5Tests {
@Test
void myFirstTest() {
assertEquals(2, 1 + 1);
}
}
3.1. Annotations
JUnit 5 supports the following annotations for configuring tests and extending the framework.
All core annotations are located in the org.junit.gen5.api
package in the junit5-api
module.
Annotation | Description |
---|---|
|
Denotes that a method is a test method. Unlike JUnit 4’s |
|
Declares a custom display name for the test class or test method |
|
Denotes that the annotated method should be executed before each |
|
Denotes that the annotated method should be executed after each |
|
Denotes that the annotated method should be executed before all |
|
Denotes that the annotated method should be executed after all |
|
Denotes that the annotated class is a nested test class. |
|
Used to declare tags for filtering tests, either at the class or method level; analogous to test groups in TestNG or Categories in JUnit 4 |
|
Used to disable a test class or test method; analogous to JUnit 4’s |
|
Used to register custom extensions to the framework. |
3.1.1. Meta-Annotations and Composed Annotations
JUnit 5 annotations can be used as meta-annotations. That means that you can define your own composed annotation that will automatically inherit the semantics of its meta-annotations.
For example, instead of copying and pasting @Tag("fast")
throughout your code base (see
Tagging and Filtering), you can create a custom composed annotation named @Fast
as follows. @Fast
can then be used as a drop-in replacement for @Tag("fast")
.
import java.lang.annotation.*;
import org.junit.gen5.api.*;
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Tag("fast")
public @interface Fast {
}
3.2. Standard Test Class
import org.junit.gen5.api.*;
class StandardTests {
@BeforeAll
static void initAll() {
}
@BeforeEach
void init() {
}
@Test
void succeedingTest() {
}
@AfterEach
void tearDown() {
}
@AfterAll
static void tearDownAll() {
}
}
Notice that neither the test class nor the test method need to be public
. @BeforeAll
and @AfterAll
must be static methods.
3.3. Custom Names
Test classes and test methods can declare a custom name — with spaces, special characters, and even emojis — that will be displayed by test runners and test reporting:
import org.junit.gen5.api.*;
@DisplayName("A special test case")
class CanHaveAnyDisplayNameTest {
@Test
@DisplayName("A nice name, isn't it?")
void testWithANiceName() {}
}
3.4. Assertions
JUnit 5 comes with many of the assertion methods that JUnit 4 has and adds a few that
lend themselves well to being used with Java 8 lambdas. All JUnit 5 assertions are static
methods in the org.junit.gen5.Assertions
class.
import static org.junit.gen5.api.Assertions.*;
import org.junit.gen5.api.*;
class MyTest {
@Test
void standardAssertions() {
assertEquals(2, 2);
assertEquals(4, 4, "The optional assertion message is now the last parameter.");
assertTrue(2 == 2, () -> "Assertion messages can be lazily evaluated -- " +
"to avoid constructing complex messages unnecessarily.");
}
@Test
void groupedAssertions() {
// In a grouped assertion all assertions are executed, and any
// failures will be reported together.
assertAll("address",
() -> assertEquals("Johannes", address.getFirstName()),
() -> assertEquals("Link", address.getLastName())
);
}
@Test
void exceptionTesting() {
Throwable exception == expectThrows(IllegalArgumentException.class,
() -> throw new IllegalArgumentException("a message")
);
assertEquals("a message", exception.getMessage());
}
}
3.5. Assumptions
JUnit 5 comes with a subset of the assumption methods that JUnit 4 provides and adds a
few that lend themselves well to being used with Java 8 lambdas. All JUnit 5 assumptions
are static methods in the org.junit.gen5.Assumptions
class.
import static org.junit.gen5.api.Assertions.*;
import static org.junit.gen5.api.Assumptions.*;
import org.junit.gen5.api.*;
class MyTest {
@Test
void testOnlyOnCiServer() {
assumeTrue("CI".equals(System.getenv("ENV"));
// remainder of test
}
@Test
void testOnlyOnDeveloperWorkstation() {
assumeTrue("DEV".equals(System.getenv("ENV"),
() -> "Aborting test: not on developer workstation");
// remainder of test
}
@Test
void testInAllEnvironments() {
assumingThat("CI".equals(System.getenv("ENV"), () -> {
// perform these assertions only on the CI server
assertEquals(...);
});
// perform these assertions in all environments
assertEquals(...);
}
}
3.6. Disabling Tests
Here’s a disabled test case:
import org.junit.gen5.api.*;
@Disabled
class MyTest {
@Test
void testWillBeSkipped() {}
}
And here’s a test case with a disabled test method:
import org.junit.gen5.api.*;
class MyTest {
@Disabled
@Test
void testWillBeSkipped() {}
@Test
void testWillBeExecuted() {}
}
3.7. Tagging and Filtering
Test classes and methods can be tagged. Those tags can later be used to filter test discovery and execution:
import org.junit.gen5.api.*;
@Tag("fast")
@Tag("model")
class FastModelTests {
@Test
@Tag("taxes")
void testingTaxCalculation() {}
}
3.8. Nested Tests
Nested tests give the test writer more capabilities to express the relationship among several group of tests. Here’s a somewhat contrived example:
import org.junit.gen5.api.*;
class MyObjectTest {
MyObject myObject;
@BeforeEach
void init() {
myObject == new MyObject();
}
@Test
void testEmptyObject() {}
@Nested
class WithChildren() {
@BeforeEach
void initWithChildren() {
myObject.addChild(new MyObject());
myObject.addChild(new MyObject());
}
@Test
void testObjectWithChildren() {}
}
}
Notice that only non-static inner classes can serve as nested tests. Nesting can be arbitrarily deep, and those inner classes can be considered as full members of the test class family.
For a more meaningful example have a look at TestingAStack.
3.9. Method Parameters and Dependency Injection
In all prior JUnit versions, methods were not allowed to have parameters (at least not
with the standard Runner
implementations). As one of the major changes in JUnit 5,
methods are now permitted to have parameters. This allows for greater flexibility and
enables method-level Dependency Injection.
MethodParameterResolver
defines the API for test extensions that wish to
dynamically resolve method parameters at runtime. If a @Test
, @BeforeEach
,
@AfterEach
, @BeforeAll
, or @AfterAll
method accepts a parameter, the parameter must
be resolved at runtime by a registered MethodParameterResolver
.
There is currently one built-in resolver that is registered automatically.
-
TestInfoParameterResolver
: if a method parameter is of typeTestInfo
, theTestInfoParameterResolver
will supply an instance ofTestInfo
corresponding to the current test as the value for the parameter. TheTestInfo
can then be used to retrieve information about the current test such as the test’s name or display name (as configured via@DisplayName
). This acts as a drop-in replacement for theTestName
rule from JUnit 4. SeeTestInfoTests
for an example.
import static org.junit.gen5.api.Assertions.*;
import org.junit.gen5.api.*;
import static org.junit.gen5.api.Assertions.assertEquals;
import static org.junit.gen5.api.Assertions.assertTrue;
import org.junit.gen5.api.BeforeEach;
import org.junit.gen5.api.DisplayName;
import org.junit.gen5.api.Test;
import org.junit.gen5.api.TestInfo;
class TestInfoTests {
@BeforeEach
void init(TestInfo testInfo) {
String displayName = testInfo.getDisplayName();
assertTrue(displayName.equals("TEST 1") || displayName.equals("test2"));
}
@Test
@DisplayName("TEST 1")
void test1(TestInfo testInfo) {
assertEquals("TEST 1", testInfo.getDisplayName());
}
@Test
void test2() {
}
}
Other parameter resolvers must be explicitly enabled by registering a test extension via @ExtendWith
.
-
Check out the
methodInjectionTest(…)
test method inSampleTestCase
for an example that uses the built-inTestInfoParameterResolver
as well as two user-provided resolvers,CustomTypeParameterResolver
andCustomAnnotationParameterResolver
. -
The
MockitoExtension
is another example of aMethodParameterResolver
. While not intended to be production-ready, it demonstrates the simplicity and expressiveness of both the extension model and the parameter resolution process.MyMockitoTest
demonstrates how to inject Mockito mocks into@BeforeEach
and@Test
methods.
import org.junit.gen5.api.*;
import static org.mockito.Mockito.when;
import com.example.mockito.MockitoExtension;
@ExtendWith(MockitoExtension.class)
class MyMockitoTest {
@BeforeEach
void init(@InjectMock Person person) {
when(person.getName()).thenReturn("Dilbert");
}
@Test
void simpleTestWithInjectedMock(@InjectMock Person person) {
assertEquals("Dilbert", person.getName());
}
}
4. Running Tests
4.1. IDE Support
At this stage there is no direct support for running JUnit 5 tests in IDEs. However, we
provide two intermediate solutions so that you can go ahead and try out the current
snapshot today. You can use the ConsoleRunner
or execute JUnit 5
tests with a JUnit 4 style runner.
4.2. Build Support
4.2.1. Gradle
The JUnit team has developed a very basic JUnit5Plugin
that lets you run JUnit 4 and
JUnit 5 tests in Gradle builds. See build.gradle
in the junit5-gradle-consumer
project for an example of the plugin in action.
Enabling the JUnit5Plugin
To use the JUnit5Plugin
, you first need to configure build.gradle
as follows.
buildscript {
repositories {
maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }
}
dependencies {
classpath 'org.junit:junit-gradle:5.0.0-SNAPSHOT'
}
}
apply plugin: 'org.junit.gen5.gradle'
Configuring the JUnit5Plugin
Once the JUnit5Plugin
has been applied, you can configure it as follows.
Caution: These options are very likely to change as we continue to work towards the final release.
junit5 {
version '5.0.0-SNAPSHOT'
runJunit4 true
matchClassName '.*Test'
includeTag 'fast'
}
Setting runJunit4
to true
instructs the JUnit5Plugin
to run JUnit 4 based tests as
well. However, you will still need to configure a testCompile
dependency on JUnit 4 in
your project similar to the following.
dependencies {
testCompile('junit:junit:4.12')
}
If you supply a tag to the includeTag
configuration method, the JUnit5Plugin
will
only run JUnit 5 based tests that are tagged accordingly via the @Tag
annotation.
Using the JUnit5Plugin
Once the JUnit5Plugin
has been applied and configured, you have a new junit5Test
task
at your disposal.
Invoking gradlew clean junit5Test
(or gradlew clean check
) from the command line will
execute all tests within the project whose class names match the regular expression
supplied via matchClassName
.
Executing the junit5Test
task in the junit5-gradle-consumer
project results in
output similar to the following:
:junit5Test Test run finished after 50 ms [ 3 tests found ] [ 2 tests started ] [ 1 tests skipped ] [ 0 tests aborted ] [ 2 tests successful] [ 0 tests failed ] BUILD SUCCESSFUL
If a test fails, the build will fail with output similar to the following:
:junit5Test Test failures (1): junit5:com.example.project.SecondTest:mySecondTest com.example.project.SecondTest#mySecondTest => Exception: 2 is not equal to 1 ==> expected:<2> but was:<1> Test run finished after 50 ms [ 3 tests found ] [ 3 tests started ] [ 0 tests skipped ] [ 0 tests aborted ] [ 2 tests successful] [ 1 tests failed ] :junit5Test FAILED FAILURE: Build failed with an exception. * What went wrong: Execution failed for task ':junit5Test'. > Process 'command '/Library/Java/JavaVirtualMachines/jdk1.8.0_66.jdk/Contents/Home/bin/java'' finished with non-zero exit value 1
Note: the exit value corresponds to the number of tests failed.
Current Limitations of the JUnit5Plugin
-
Even though the build will fail if a test fails, the results will not be included in the test report generated by Gradle.
-
With
runJunit4
set totrue
, theJUnit5Plugin
takes over the responsibility of running JUnit 4 tests, and thecheck
Gradle task will no longer depend on the Gradletest
task. Consequently, the results for JUnit 4 tests will not be included in the test report generated by Gradle.
4.2.2. Maven
The JUnit team has developed a very basic provider for Maven Surefire that lets you run
JUnit 4 and JUnit 5 tests via mvn test
. The pom.xml
file in the
junit5-maven-consumer
project demonstrates how to use it and can serve as a starting
point.
...
<build>
<plugins>
...
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19</version>
<dependencies>
<dependency>
<groupId>org.junit</groupId>
<artifactId>surefire-junit5</artifactId>
<version>5.0.0-SNAPSHOT</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
...
4.3. Console Runner
The ConsoleRunner
is a command-line Java application that lets you run JUnit 4 and
JUnit 5 tests and prints test execution results to the console.
Here’s an example of its output:
Test execution started. Number of static tests: 2 Engine started: junit5 Test started: My 1st JUnit 5 test! 😎 [junit5:com.example.project.FirstTest#myFirstTest(java.lang.String)] Test succeeded: My 1st JUnit 5 test! 😎 [junit5:com.example.project.FirstTest#myFirstTest(java.lang.String)] Test skipped: mySecondTest [junit5:com.example.project.SecondTest#mySecondTest()] => Exception: Skipped test method [void com.example.project.SecondTest.mySecondTest()] due to failed condition Engine finished: junit5 Test execution finished. Test run finished after 29 ms [ 2 tests found ] [ 1 tests started ] [ 1 tests skipped ] [ 0 tests aborted ] [ 1 tests successful] [ 0 tests failed ]
4.3.1. Options
Caution: These options are very likely to change as we continue to work towards the final release.
Option Description ------ ----------- -C, --disable-ansi-colors Disable colored output (not supported by all terminals) -D, --hide-details Hide details while tests are being executed. Only show the summary and test failures. -T, --exclude-tags Give a tag to include in the test run. This option can be repeated. -a, --all Run all tests -h, --help Display help information -n, --filter-classname Give a regular expression to include only classes whose fully qualified names match. -p, --classpath Additional classpath entries, e.g. for adding engines and their dependencies -t, --filter-tags Give a tag to include in the test run. This option can be repeated. -x, --enable-exit-code Exit process with number of failing tests as exit code
4.4. Using JUnit 4 to Run JUnit 5 Tests
The JUnit5
runner lets you run JUnit 5 tests with JUnit 4. This way you can run JUnit 5
tests in IDEs and build tools that only know about JUnit 4. As soon as we add reporting
features to JUnit 5 that JUnit 4 does not have, the runner will only be able to support a
subset of the JUnit 5 functionality. But for the time being the JUnit5
runner is an
easy way to get started.
4.4.1. Setup
You need the following artifacts and their dependencies on the classpath. See Dependency Metadata for details regarding group IDs, artifact IDs, and versions.
-
junit5-api
in test scope: API for writing tests, including@Test
, etc. -
junit4-runner
in test scope: location of theJUnit5
runner -
junit5-engine
in test runtime scope: implementation of the Engine API for JUnit 5
4.4.2. Single Test Class
One way to use the JUnit5
runner is to annotate a JUnit 5 test class with
@RunWith(JUnit5.class)
directly. Please note that the tests are annotated with
org.junit.gen5.api.Test
(JUnit 5), not org.junit.Test
(JUnit 4). Moreover, in this
case the test class must be public
because; otherwise, the IDEs won’t recognize it as a
test class.
package com.example;
import static org.junit.gen5.api.Assertions.fail;
import org.junit.gen5.api.Test;
import org.junit.gen5.junit4runner.JUnit5;
import org.junit.runner.RunWith;
@RunWith(JUnit5.class)
public class AJUnit5TestCaseRunWithJUnit4 {
@Test
void aSucceedingTest() {
/* no-op */
}
@Test
void aFailingTest() {
fail("Failing for failing's sake.");
}
}
4.4.3. Multiple Tests
If you have multiple JUnit 5 tests you can create a test suite.
package com.example;
import org.junit.gen5.junit4runner.JUnit5;
import org.junit.gen5.junit4runner.JUnit5.Packages;
import org.junit.runner.RunWith;
@RunWith(JUnit5.class)
@Packages("com.example")
public class JUnit4SamplesSuite {
}
The JUnit4SamplesSuite
will discover and run all tests in the com.example
package
and its subpackages.
5. Extension Model
5.1. Overview
In contrast to the competing Runner
, @Rule
, and @ClassRule
extension points in
JUnit 4, the JUnit 5 extension model consists of a single, coherent concept: the
TestExtension
API. Note, however, that TestExtension
itself is just a marker
interface.
5.2. Registering Extensions
Developers can register one or more extensions by annotating a test class or test method
with @ExtendWith(…)
, supplying class references for the extensions to register. For
example, to register a custom MockitoExtension
, you would annotate your test class as
follows.
@ExtendWith(MockitoExtension.class)
class MockTests {
// ...
}
Multiple extensions can be registered together like this:
@ExtendWith({ FooExtension.class, BarExtension.class })
class MyTestsV1 {
// ...
}
As an alternative, multiple extensions can be registered separately like this:
@ExtendWith(FooExtension.class)
@ExtendWith(BarExtension.class)
class MyTestsV2 {
// ...
}
The execution of tests in both MyTestsV1
and MyTestsV2
will be extended by the
FooExtension
and BarExtension
, in exactly that order.
Registered extensions are inherited within test class hierarchies.
5.3. Conditional Test Execution
ContainerExecutionCondition
and TestExecutionCondition
define the TestExtension
APIs for programmatic, conditional test execution.
A ContainerExecutionCondition
is evaluated to determine if all tests in a given
container (e.g., a test class) should be executed based on the supplied
ContainerExtensionContext
. Similarly, a TestExecutionCondition
is evaluated to
determine if a given test method should be executed based on the supplied
TestExtensionContext
.
See the source code of DisabledCondition
and @Disabled
for concrete examples.
5.4. Test Instance Post-processing
InstancePostProcessor
defines the API for TestExtensions
that wish to post
process test instances.
Common use cases include injecting dependencies into the test instance, invoking custom initialization methods on the test instance, etc.
For concrete examples, consult the source code for the MockitoExtension
and the
SpringExtension
.
5.5. Parameter Resolution
MethodParameterResolver
is a TestExtension
strategy for dynamically resolving
method parameters at runtime.
If a @Test
, @BeforeEach
, @AfterEach
, @BeforeAll
or @AfterAll
method accepts a
parameter, the parameter must be resolved at runtime by a MethodParameterResolver
. A
MethodParameterResolver
can either be built-in (see {TestNameParameterResolver}
) or
registered by the user via @ExtendWith
. Generally speaking, parameters may be resolved
by type or by annotation. For concrete examples, consult the source code for
CustomTypeParameterResolver
and CustomAnnotationParameterResolver
, respectively.
5.6. Test Lifecycle Callbacks
The following interfaces define the APIs for extending tests at various points in the
test execution lifecycle. Consult the Javadoc for each of these in the
org.junit.gen5.api.extension
package.
-
BeforeEachExtensionPoint
-
AfterEachExtensionPoint
-
BeforeAllExtensionPoint
-
AfterAllExtensionPoint
Note that extension developers may choose to implement any number of these interfaces
within a single extension. Consult the source code of the SpringExtension
for a
concrete example.
5.7. Extension Point Application Order
Sometimes you want to influence the order in which several extensions of the same type are applied.
This goal can be achieved by implementing the ExtensionRegistrar
interface…
5.8. Keeping State in Extensions
Usually, an extension is instantiated only once. So the question becomes relevant: How do you keep the state from one invocation of an extension point to the next? …
5.9. Additional Planned Extension Points
Several additional extension points are planned, including but not limited to the following.
-
Dynamic test registration – for example, for computing parameterized tests at runtime
6. Migrating from JUnit 4
Although the JUnit 5 programming model and extension model will not support JUnit 4
features such as Rules
and Runners
, it is not expected that source code maintainers
will need to update all of their existing tests, test extensions, and custom build test
infrastructure to migrate to JUnit 5.
Instead, JUnit 5 provides a gentle migration path via a JUnit 4 test engine which
allows existing tests based on JUnit 4 to be executed using the JUnit 5 infrastructure.
Since all classes and annotations specific to JUnit 5 reside under a new org.junit.gen5
base package, having both JUnit 4 and JUnit 5 in the classpath does not lead to any
conflicts. It is therefore safe to maintain existing JUnit 4 tests alongside JUnit 5
tests. Furthermore, since the JUnit team will continue to provide maintenance and bug fix
releases for the JUnit 4.x baseline, developers have plenty of time to migrate to JUnit 5
on their own schedule.
6.1. Running JUnit 4 Tests with JUnit 5
Just make sure that the junit4-engine
artifact is in your test runtime path. In that
case JUnit 4 tests will automatically be picked up by JUnit 5 test runners.
See the example projects in the junit5-samples repository to find out how this is done with Gradle and Maven.
6.2. Migration Tips
The following are things you have to watch out for when migrating existing JUnit 4 tests to JUnit 5.
-
Annotations reside in the
org.junit.gen5.api
package. -
Assertions reside in
org.junit.gen5.api.Assertions
. -
Assumptions reside in
org.junit.gen5.api.Assumptions
. -
@Before
and@After
no longer exist; use@BeforeEach
and@AfterEach
instead. -
@BeforeClass
and@AfterClass
no longer exist; use@BeforeAll
and@AfterAll
instead. -
@Ignore
no longer exists: use@Disabled
instead. -
@Category
no longer exists; use@Tag
instead. -
@RunWith
no longer exists; superseded by@ExtendWith
. -
@Rule
and@ClassRule
no longer exist; superseded by@ExtendWith
.
7. Advanced Topics
7.1. The JUnit 5 Launcher API
One of the prominent goals of JUnit 5 is to make the interface between JUnit and its programmatic clients – build tools and IDEs – more powerful and stable. The purpose is to decouple the internals of discovering and executing tests from all the filtering and configuration that’s necessary from the outside.
For JUnit 5 we came up with the concept of a Launcher
that can be used to discover,
filter, and execute JUnit tests. Moreover, we added a mechanism to allow third party test
libraries – like Spock, Cucumber, and FitNesse – to plug into JUnit 5’s launching
infrastructure.
The launching API is in the junit-launcher
module.
An example consumer of the launching API is the ConsoleRunner
in the
junit-console
project.
7.1.1. Discovering Tests
Introducing test discovery as a dedicated feature of JUnit itself will (hopefully) free IDEs and build tools from most of the difficulties they had to go through to identify test classes and test methods in the past.
Usage Example:
import static org.junit.gen5.engine.TestPlanSpecification.*;
TestPlanSpecification specification = build(
forPackage("com.mycompany.mytests"),
forClass(MyTestClass.class)
).filterWith(classNameMatches("*Test").or(classNameMatches("Test*")));
TestPlan plan = new Launcher().discover(specification);
There’s currently the possibility to search for classes, methods, all classes in a package, or even all tests in the classpath. Discovery takes place across all participating test engines.
The resulting test plan is basically a hierarchical (and read-only) description of all
engines, classes, and test methods that fit the specification
object. The client can
traverse the tree, retrieve details about a node, and get a link to the original source
(like class, method, or file position). Every node in the test plan tree has a unique
ID that can be used to invoke a particular test or group of tests.
7.1.2. Running Tests
There are two ways to execute tests. Clients can either use the same test specification
object as in the discovery phase, or – to speed things up a bit – pass in the prepared
TestPlan
object from a previous discovery step. Test progress and result reporting can
be achieved through a TestExecutionListener
:
TestPlanSpecification specification = build(
forPackage("com.mycompany.mytests"),
forClass(MyTestClass.class)
).filterWith(classNameMatches("*Test").or(classNameMatches("Test*")));
Launcher launcher = new Launcher();
TestPlanExecutionListener listener = createListener();
launcher.registerTestPlanExecutionListener(listener);
launcher.execute(specification);
There’s currently no result object, but you can easily use a listener to aggregate the
final results in an object of your own. For an example see the
SummaryGeneratingListener
.
7.1.3. Plugging in Your Own Test Engine
The current snapshot provides two TestEngine
implementations out of the box:
-
junit5-engine
: The core of JUnit 5. -
junit4-engine
: A thin layer on top of JUnit 4 to allow running "old" tests with the launcher infrastructure.
Third parties may also contribute their own TestEngine
by implementing the interfaces in the
junit-engine-api
project and registering their engine. Engine registration is currently supported via
Java’s java.util.ServiceLoader
mechanism. For example, the junit5-engine
project
registers its JUnit5TestEngine
here.