Skip to content

Latest commit

 

History

History
95 lines (73 loc) · 4.19 KB

launcher-api.adoc

File metadata and controls

95 lines (73 loc) · 4.19 KB

JUnit Platform 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.

JUnit 5 introduces the concept of a Launcher that can be used to discover, filter, and execute tests. Moreover, third party test libraries – like Spock, Cucumber, and FitNesse – can plug into the JUnit Platform’s launching infrastructure by providing a custom {TestEngine}.

The launching API is in the {junit-platform-launcher} module.

An example consumer of the launching API is the {ConsoleLauncher} in the {junit-platform-console} project.

Discovering Tests

Introducing test discovery as a dedicated feature of the platform 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:

link:{testDir}/example/UsingTheLauncherDemo.java[role=include]
link:{testDir}/example/UsingTheLauncherDemo.java[role=include]

There’s currently the possibility to select classes, methods, and all classes in a package or even search for all tests in the classpath. Discovery takes place across all participating test engines.

The resulting TestPlan is a hierarchical (and read-only) description of all engines, classes, and test methods that fit the LauncherDiscoveryRequest. 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 has a unique ID that can be used to invoke a particular test or group of tests.

Executing Tests

To execute tests, clients can use the same LauncherDiscoveryRequest as in the discovery phase or create a new request. Test progress and reporting can be achieved by registering one or more {TestExecutionListener} implementations with the Launcher as in the following example.

link:{testDir}/example/UsingTheLauncherDemo.java[role=include]

There is no return value for the execute() method, but you can easily use a listener to aggregate the final results in an object of your own. For an example see the {SummaryGeneratingListener}.

Plugging in Your Own Test Engine

JUnit currently provides two {TestEngine} implementations out of the box:

  • {junit-jupiter-engine}: The core of JUnit Jupiter.

  • {junit-vintage-engine}: A thin layer on top of JUnit 4 to allow running vintage tests with the launcher infrastructure.

Third parties may also contribute their own TestEngine by implementing the interfaces in the {junit-platform-engine} module and registering their engine. Engine registration is currently supported via Java’s java.util.ServiceLoader mechanism. For example, the junit-jupiter-engine module registers its org.junit.jupiter.engine.JupiterTestEngine in a file named org.junit.platform.engine.TestEngine within the /META-INF/services in the junit-jupiter-engine JAR.

Note
{HierarchicalTestEngine} is a convenient abstract base implementation (used by the {junit-jupiter-engine}) that only requires implementors to provide the logic for test discovery. It implements execution of TestDescriptors that implement the Node interface, including support for parallel execution.

Plugging in Your Own Test Execution Listeners

In addition to the public {Launcher} API method for registering test execution listeners programmatically, custom {TestExecutionListener} implementations discovered at runtime via Java’s java.util.ServiceLoader facility are automatically registered with the DefaultLauncher. For example, an example.TestInfoPrinter class implementing {TestExecutionListener} and declared within the /META-INF/services/org.junit.platform.launcher.TestExecutionListener file is loaded and registered automatically.