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.

3. Writing Tests

A first test case
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

@Test

Denotes that a method is a test method. Unlike JUnit 4’s @Test annotation, this annotation does not declare any attributes, since test extensions in JUnit 5 operate based on their own dedicated annotations.

@DisplayName

Declares a custom display name for the test class or test method

@BeforeEach

Denotes that the annotated method should be executed before each @Test method in the current class or class hierarchy

@AfterEach

Denotes that the annotated method should be executed after each @Test method in the current class or class hierarchy

@BeforeAll

Denotes that the annotated method should be executed before all @Test methods in the current class or class hierarchy; analogous to JUnit 4’s @BeforeClass. Such methods must be static.

@AfterAll

Denotes that the annotated method should be executed after all @Test methods in the current class or class hierarchy; analogous to JUnit 4’s @AfterClass. Such methods must be static.

@Nested

Denotes that the annotated class is a nested test class.

@Tag and @Tags

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

@Disabled

Used to disable a test class or test method; analogous to JUnit 4’s @Ignore

@ExtendWith

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

A simple standard test case
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 type TestInfo, the TestInfoParameterResolver will supply an instance of TestInfo corresponding to the current test as the value for the parameter. The TestInfo 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 the TestName rule from JUnit 4. See TestInfoTests 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.

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 to true, the JUnit5Plugin takes over the responsibility of running JUnit 4 tests, and the check Gradle task will no longer depend on the Gradle test 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 the JUnit5 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.

There are more configuration options for discovering and filtering tests than just @Packages. Please consult the Javadoc or the source code for the JUnit5 runner for further details.

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.

7.2. Modules

7.3. Engines