= JUnit Platform Launcher API

One of the prominent goals of the JUnit Platform 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 is necessary from the outside.

JUnit Platform provides a `Launcher` API that can be used to discover, filter, and execute
tests. Moreover, third party test libraries – like Spock or Cucumber – can plug into the
JUnit Platform's launching infrastructure by providing a custom
xref:advanced-topics/engines.adoc[TestEngine].

image::launcher-api-diagram.svg[role=text-center]

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

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

[[discovery]]
== Discovering Tests

Having _test discovery_ as a dedicated feature of the platform frees IDEs and build tools
from most of the difficulties they had to go through to identify test classes and test
methods in previous versions of JUnit.

Usage Example:

[source,java,indent=0]
----
include::example$java/example/UsingTheLauncherForDiscoveryDemo.java[tags=imports]
----

[source,java,indent=0]
----
include::example$java/example/UsingTheLauncherForDiscoveryDemo.java[tags=discovery]
----

You can select classes, methods, and all classes in a package or even search for all tests
in the class-path or module-path. 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.

Clients can register one or more `{LauncherDiscoveryListener}` implementations via the
`{LauncherDiscoveryRequestBuilder}` to gain insight into events that occur during test
discovery. By default, the builder registers an "abort on failure" listener that aborts
test discovery after the first discovery failure is encountered. The default
`LauncherDiscoveryListener` can be changed via the
`junit.platform.discovery.listener.default` xref:running-tests/configuration-parameters.adoc[configuration
parameter].

[[execution]]
== 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.

[source,java,indent=0]
----
include::example$java/example/UsingTheLauncherDemo.java[tags=execution]
----

There is no return value for the `execute()` method, but you can use a
`TestExecutionListener` to aggregate the results. For examples see the
`{SummaryGeneratingListener}`, `{LegacyXmlReportGeneratingListener}`, and
`{UniqueIdTrackingListener}`.

NOTE: All `TestExecutionListener` methods are called sequentially. Methods for start
events are called in registration order while methods for finish events are called in
reverse order.
Test case execution won't start before all `executionStarted` calls have returned.

[[engines-custom]]
== Registering a TestEngine

See the dedicated section on xref:advanced-topics/engines.adoc#registration[TestEngine registration] for
details.

[[post-discovery-filters-custom]]
== Registering a PostDiscoveryFilter

In addition to specifying post-discovery filters as part of a `{LauncherDiscoveryRequest}`
passed to the `{Launcher}` API, `{PostDiscoveryFilter}` implementations will be discovered
at runtime via Java's `{ServiceLoader}` mechanism and automatically applied by the
`Launcher` in addition to those that are part of the request.

For example, an `example.CustomTagFilter` class implementing `PostDiscoveryFilter` and
declared within the `/META-INF/services/org.junit.platform.launcher.PostDiscoveryFilter`
file is loaded and applied automatically.

[[launcher-session-listeners-custom]]
== Registering a LauncherSessionListener

Registered implementations of `{LauncherSessionListener}` are notified when a
`{LauncherSession}` is opened (before a `{Launcher}` first discovers and executes tests)
and closed (when no more tests will be discovered or executed). They can be registered
programmatically via the `{LauncherConfig}` that is passed to the `{LauncherFactory}`, or
they can be discovered at runtime via Java's `{ServiceLoader}` mechanism and automatically
registered with `LauncherSession` (unless automatic registration is disabled.)

[[launcher-session-listeners-tool-support]]
=== Tool Support

The following build tools and IDEs are known to provide full support for `LauncherSession`:

* Gradle 4.6 and later
* Maven Surefire/Failsafe 3.0.0-M6 and later
* IntelliJ IDEA 2017.3 and later

Other tools might also work but have not been tested explicitly.

[[launcher-session-listeners-tool-example-usage]]
=== Example Usage

A `LauncherSessionListener` is well suited for implementing once-per-JVM setup/teardown
behavior since it's called before the first and after the last test in a launcher session,
respectively. The scope of a launcher session depends on the used IDE or build tool but
usually corresponds to the lifecycle of the test JVM. A custom listener that starts an
HTTP server before executing the first test and stops it after the last test has been
executed, could look like this:

[source,java]
.src/test/java/example/session/GlobalSetupTeardownListener.java
----
package example.session;

include::example$java/example/session/GlobalSetupTeardownListener.java[tags=user_guide]
----
<1> Get the store from the launcher session
<2> Lazily create the HTTP server and put it into the store
<3> Start the HTTP server

It uses a wrapper class to ensure the server is stopped when the launcher session is
closed:

[source,java]
.src/test/java/example/session/CloseableHttpServer.java
----
package example.session;

include::example$java/example/session/CloseableHttpServer.java[tags=user_guide]
----
<1> The `close()` method is called when the launcher session is closed
<2> Stop the HTTP server

This sample uses the HTTP server implementation from the jdk.httpserver module that comes
with the JDK but would work similarly with any other server or resource. In order for the
listener to be picked up by JUnit Platform, you need to register it as a service by adding
a resource file with the following name and contents to your test runtime classpath (e.g.
by adding the file to `src/test/resources`):

[source]
.src/test/resources/META-INF/services/org.junit.platform.launcher.LauncherSessionListener
----
include::example$resources/META-INF/services/org.junit.platform.launcher.LauncherSessionListener[]
----

You can now use the resource from your test:

[source,java]
.src/test/java/example/session/HttpTests.java
----
package example.session;

include::example$java/example/session/HttpTests.java[tags=user_guide]
----
<1> Retrieve the HTTP server instance from the store
<2> Get the host string directly from the injected HTTP server instance
<3> Get the port number directly from the injected HTTP server instance
<4> Send a request to the server
<5> Check the status code of the response

[[launcher-interceptors-custom]]
== Registering a LauncherInterceptor

In order to intercept the creation of instances of `{Launcher}` and
`{LauncherSessionListener}` and calls to the `discover` and `execute` methods of the
former, clients can register custom implementations of `{LauncherInterceptor}` via Java's
`{ServiceLoader}` mechanism by setting the
`junit.platform.launcher.interceptors.enabled` xref:running-tests/configuration-parameters.adoc[configuration parameter] to `true`.

[NOTE]
====
Since interceptors are registered before the test run starts, the
`junit.platform.launcher.interceptors.enabled` _configuration parameter_ can only be
supplied as a JVM system property or via the JUnit Platform configuration file (see
xref:running-tests/configuration-parameters.adoc[] for details). This _configuration parameter_ cannot be
supplied in the `LauncherDiscoveryRequest` that is passed to the `{Launcher}`.
====


A typical use case is to create a custom interceptor to replace the `ClassLoader` used by
the JUnit Platform to load test classes and engine implementations.

[source,java]
----
include::example$java/example/CustomLauncherInterceptor.java[tags=user_guide]
----

[[launcher-discovery-listeners-custom]]
== Registering a LauncherDiscoveryListener

In addition to specifying discovery listeners as part of a `{LauncherDiscoveryRequest}` or
registering them programmatically via the `{Launcher}` API, custom
`LauncherDiscoveryListener` implementations can be discovered at runtime via Java's
`{ServiceLoader}` mechanism and automatically registered with the `Launcher` created via
the `{LauncherFactory}`.

For example, an `example.CustomLauncherDiscoveryListener` class implementing
`LauncherDiscoveryListener` and declared within the
`/META-INF/services/org.junit.platform.launcher.LauncherDiscoveryListener` file is loaded
and registered automatically.

[[listeners-custom]]
== Registering a TestExecutionListener

In addition to the public `{Launcher}` API method for registering test execution listeners
programmatically, custom `{TestExecutionListener}` implementations will be discovered at
runtime via Java's `{ServiceLoader}` mechanism and automatically registered with the
`Launcher` created via the `{LauncherFactory}`.

For example, an `example.CustomTestExecutionListener` class implementing
`TestExecutionListener` and declared within the
`/META-INF/services/org.junit.platform.launcher.TestExecutionListener` file is loaded and
registered automatically.

[[listeners-config]]
== Configuring a TestExecutionListener

When a `{TestExecutionListener}` is registered programmatically via the `{Launcher}` API,
the listener may provide programmatic ways for it to be configured -- for example, via its
constructor, setter methods, etc. However, when a `TestExecutionListener` is registered
automatically via Java's `ServiceLoader` mechanism (see
<<listeners-custom>>), there is no way for the user to directly configure the
listener. In such cases, the author of a `TestExecutionListener` may choose to make the
listener configurable via xref:running-tests/configuration-parameters.adoc[configuration parameters]. The
listener can then access the configuration parameters via the `TestPlan` supplied to the
`testPlanExecutionStarted(TestPlan)` and `testPlanExecutionFinished(TestPlan)` callback
methods. See the `{UniqueIdTrackingListener}` for an example.

[[listeners-custom-deactivation]]
== Deactivating a TestExecutionListener

Sometimes it can be useful to run a test suite _without_ certain execution listeners being
active. For example, you might have custom a `{TestExecutionListener}` that sends the test
results to an external system for reporting purposes, and while debugging you might not
want these _debug_ results to be reported. To do this, provide a pattern for the
`junit.platform.execution.listeners.deactivate` _configuration parameter_ to specify which
execution listeners should be deactivated (i.e. not registered) for the current test run.

[NOTE]
====
Only listeners registered via the `{ServiceLoader}` mechanism within the
`/META-INF/services/org.junit.platform.launcher.TestExecutionListener` file can be
deactivated. In other words, any `TestExecutionListener` registered explicitly via the
`{LauncherDiscoveryRequest}` cannot be deactivated via the
`junit.platform.execution.listeners.deactivate` _configuration parameter_.

In addition, since execution listeners are registered before the test run starts, the
`junit.platform.execution.listeners.deactivate` _configuration parameter_ can only be
supplied as a JVM system property or via the JUnit Platform configuration file (see
xref:running-tests/configuration-parameters.adoc[] for details). This _configuration parameter_ cannot be
supplied in the `LauncherDiscoveryRequest` that is passed to the `{Launcher}`.
====

[[listeners-custom-deactivation-pattern]]
=== Pattern Matching Syntax

Refer to xref:running-tests/configuration-parameters.adoc#pattern[Pattern Matching Syntax] for details.

[[launcher-config]]
== Configuring the Launcher

If you require fine-grained control over automatic detection and registration of test
engines and listeners, you may create an instance of `{LauncherConfig}` and supply that to
the `{LauncherFactory}`. Typically, an instance of `LauncherConfig` is created via the
built-in fluent _builder_ API, as demonstrated in the following example.

[source,java,indent=0]
----
include::example$java/example/UsingTheLauncherDemo.java[tags=launcherConfig]
----

[[dry-run-mode]]
== Dry-Run Mode

When running tests via the `{Launcher}` API, you can enable _dry-run mode_ by setting the
`junit.platform.execution.dryRun.enabled` xref:running-tests/configuration-parameters.adoc[configuration parameter] to `true`. In this mode, the `{Launcher}` will not actually
execute any tests but will notify registered `{TestExecutionListener}` instances as if all
tests had been skipped and their containers had been successful. This can be useful to
test changes in the configuration of a build or to verify a listener is called as expected
without having to wait for all tests to be executed.

[[managing-state-across-test-engines]]
== Managing State Across Test Engines

When running tests on the JUnit Platform, multiple test engines may need to access shared
resources. Rather than initializing these resources multiple times, JUnit Platform
provides mechanisms to share state across test engines efficiently. Test engines can use
the Platform's `{NamespacedHierarchicalStore}` API to lazily initialize and share
resources, ensuring they are created only once regardless of execution order. Any resource
that is put into the store and implements `AutoCloseable` will be closed automatically when
the execution is finished.

TIP: The Jupiter engine allows read and write access to such resources via its
`{ExtensionContext_Store}` API.

The following example demonstrates two custom test engines sharing a `ServerSocket`
resource. `FirstCustomEngine` attempts to retrieve an existing `ServerSocket` from the
global store or creates a new one if it doesn't exist:

[source,java]
----
include::example$java/example/FirstCustomEngine.java[tags=user_guide]
----

`SecondCustomEngine` follows the same pattern, ensuring that regardless whether it runs
before or after `FirstCustomEngine`, it will use the same socket instance:

[source,java]
----
include::example$java/example/SecondCustomEngine.java[tags=user_guide]
----

TIP: In this case, the `ServerSocket` can be stored directly in the global store while
ensuring since it gets closed because it implements `AutoCloseable`. If you need to use a
type that does not do so, you can wrap it in a custom class that implements
`AutoCloseable` and delegates to the original type. This is important to ensure that the
resource is closed properly when the test run is finished.

For illustration, the following test verifies that both engines are sharing the same
`ServerSocket` instance and that it's closed after `Launcher.execute()` returns:

[source,java,indent=0]
----
include::example$java/example/sharedresources/SharedResourceDemo.java[tags=user_guide]
----

By using the Platform's `{NamespacedHierarchicalStore}` API with shared namespaces in this
way, test engines can coordinate resource creation and sharing without direct dependencies
between them.

Alternatively, it's possible to inject resources into test engines by
<<launcher-session-listeners-custom, registering a `LauncherSessionListener`>>.

[[launcher-cancellation]]
== Cancelling a Running Test Execution

The launcher API provides the ability to cancel a running test execution mid-flight while
allowing engines to clean up resources. To request an execution to be cancelled, you need
to call `cancel()` on the `{CancellationToken}` that is passed to `Launcher.execute` as
part of the `{LauncherExecutionRequest}`.

For example, implementing a listener that cancels test execution after the first test
failed can be achieved as follows.

[source,java,indent=0]
----
include::example$java/example/UsingTheLauncherDemo.java[tags=cancellation-direct]
----
<1> Create a `{CancellationToken}`
<2> Implement a `{TestExecutionListener}` that calls `cancel()` when a test fails
<3> Register the cancellation token
<4> Register the listener
<5> Pass the `{LauncherExecutionRequest}` to `Launcher.execute`

[NOTE]
.Test Engine Support for Cancellation
====
Cancelling tests relies on xref:advanced-topics/engines.adoc[] checking and responding to the
`{CancellationToken}` appropriately (see
xref:advanced-topics/engines.adoc#requirements-cancellation[Test Engine Requirements] for details). The
`Launcher` will also check the token and cancel test execution when multiple test engines
are present at runtime.

At the time of writing, the following test engines support cancellation:

* `{junit-jupiter-engine}`
* `{junit-vintage-engine}`
* `{junit-platform-suite-engine}`
* https://github.com/junit-team/testng-engine[`testng-engine`] (version 1.1.0 and later)
* Any `{TestEngine}` extending `{HierarchicalTestEngine}` such as Spock and Cucumber
====

[[launcher-cancellation-execution-request-from-discovery-request]]
=== Building a LauncherExecutionRequest from a LauncherDiscoveryRequest

Rather than building a `{LauncherExecutionRequest}` by starting with a
`{LauncherDiscoveryRequestBuilder}` and calling `forExecution()`, you can create a
`{LauncherExecutionRequestBuilder}` from a previously built `{LauncherDiscoveryRequest}`.

[source,java,indent=0]
----
include::example$java/example/UsingTheLauncherDemo.java[tags=cancellation-discovery-request]
----
<1> Build a `{LauncherDiscoveryRequest}`
<2> Create a `{LauncherExecutionRequestBuilder}` with it
<3> Register the cancellation token
<4> Register the listener
<5> Pass the `{LauncherExecutionRequest}` to `Launcher.execute`

[[launcher-cancellation-execution-request-from-test-plan]]
=== Building a LauncherExecutionRequest from a TestPlan

Alternatively, a `{LauncherExecutionRequestBuilder}` can be created from a previously
discovered `{TestPlan}`.

[source,java,indent=0]
----
include::example$java/example/UsingTheLauncherDemo.java[tags=cancellation-test-plan]
----
<1> Build a `{LauncherDiscoveryRequest}`
<2> Discover a `{TestPlan}` via `Launcher.discover`
<3> Create a `{LauncherExecutionRequestBuilder}` with it
<4> Register the cancellation token
<5> Register the listener
<6> Pass the `{LauncherExecutionRequest}` to `Launcher.execute`
