/*
 * Copyright 2015-2019 the original author or authors.
 *
 * All rights reserved. This program and the accompanying materials are
 * made available under the terms of the Eclipse Public License v2.0 which
 * accompanies this distribution and is available at
 *
 * http://www.eclipse.org/legal/epl-v20.html
 */

package org.junit.jupiter.api.extension;

import static org.apiguardian.api.API.Status.STABLE;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.apiguardian.api.API;

@RegisterExtension is used to register an Extension via a field in a test class.

In contrast to @ExtendWith which is used to register extensions declaratively, @RegisterExtension can be used to register an extension programmatically — for example, in order to pass arguments to the extension's constructor, static factory method, or builder API.

@RegisterExtension fields must not be private or null (when evaluated) but may be either static or non-static.

Static Fields

If a @RegisterExtension field is static, the extension will be registered after extensions that are registered at the class level via @ExtendWith. Such static extensions are not limited in which extension APIs they can implement. Extensions registered via static fields may therefore implement class-level and instance-level extension APIs such as BeforeAllCallback, AfterAllCallback, and TestInstancePostProcessor as well as method-level extension APIs such as BeforeEachCallback, etc.

Instance Fields

If a @RegisterExtension field is non-static (i.e., an instance field), the extension will be registered after the test class has been instantiated and after all TestInstancePostProcessors have been given a chance to post-process the test instance (potentially injecting the instance of the extension to be used into the annotated field). Thus, if such an instance extension implements class-level or instance-level extension APIs such as BeforeAllCallback, AfterAllCallback, or TestInstancePostProcessor those APIs will not be honored. By default, an instance extension will be registered after extensions that are registered at the method level via @ExtendWith; however, if the test class is configured with @TestInstance(Lifecycle.PER_CLASS) semantics, an instance extension will be registered before extensions that are registered at the method level via @ExtendWith.

Example Usage

In the following example, the docs field in the test class is initialized programmatically by supplying a custom lookUpDocsDir() method to a static factory method in the DocumentationExtension. The configured DocumentationExtension will be automatically registered as an extension. In addition, test methods can access the instance of the extension via the docs field if necessary.

class DocumentationTests { static Path lookUpDocsDir() { // return path to docs dir } @RegisterExtension DocumentationExtension docs = DocumentationExtension.forPath(lookUpDocsDir()); @Test void generateDocumentation() { // use docs ... } }

Registration Order

By default, if multiple extensions are registered via @RegisterExtension, they will be ordered using an algorithm that is deterministic but intentionally nonobvious. This ensures that subsequent runs of a test suite execute extensions in the same order, thereby allowing for repeatable builds. However, there are times when extensions need to be registered in an explicit order. To achieve that, annotate each @RegisterExtension field with @Order. Any @RegisterExtension field not annotated with @Order will appear at the end of the sorted list.

Supported Extension APIs

See Also:
Since:5.1
/** * {@code @RegisterExtension} is used to register an {@link Extension} via a * field in a test class. * * <p>In contrast to {@link ExtendWith @ExtendWith} which is used to register * extensions <em>declaratively</em>, {@code @RegisterExtension} can be used to * register an extension <em>programmatically</em> &mdash; for example, in order * to pass arguments to the extension's constructor, {@code static} factory * method, or builder API. * * <p>{@code @RegisterExtension} fields must not be {@code private} or * {@code null} (when evaluated) but may be either {@code static} or non-static. * * <h3>Static Fields</h3> * * <p>If a {@code @RegisterExtension} field is {@code static}, the extension * will be registered after extensions that are registered at the class level * via {@code @ExtendWith}. Such <em>static</em> extensions are not limited in * which extension APIs they can implement. Extensions registered via static * fields may therefore implement class-level and instance-level extension APIs * such as {@link BeforeAllCallback}, {@link AfterAllCallback}, and * {@link TestInstancePostProcessor} as well as method-level extension APIs * such as {@link BeforeEachCallback}, etc. * * <h3>Instance Fields</h3> * * <p>If a {@code @RegisterExtension} field is non-static (i.e., an instance * field), the extension will be registered after the test class has been * instantiated and after all {@link TestInstancePostProcessor * TestInstancePostProcessors} have been given a chance to post-process the * test instance (potentially injecting the instance of the extension to be * used into the annotated field). Thus, if such an <em>instance</em> extension * implements class-level or instance-level extension APIs such as * {@link BeforeAllCallback}, {@link AfterAllCallback}, or * {@link TestInstancePostProcessor} those APIs will not be honored. By default, * an instance extension will be registered <em>after</em> extensions that are * registered at the method level via {@code @ExtendWith}; however, if the test * class is configured with * {@link org.junit.jupiter.api.TestInstance.Lifecycle @TestInstance(Lifecycle.PER_CLASS)} * semantics, an instance extension will be registered <em>before</em> extensions * that are registered at the method level via {@code @ExtendWith}. * * <h3>Example Usage</h3> * * <p>In the following example, the {@code docs} field in the test class is * initialized programmatically by supplying a custom {@code lookUpDocsDir()} * method to a {@code static} factory method in the {@code DocumentationExtension}. * The configured {@code DocumentationExtension} will be automatically registered * as an extension. In addition, test methods can access the instance of the * extension via the {@code docs} field if necessary. * * <pre style="code"> * class DocumentationTests { * * static Path lookUpDocsDir() { * // return path to docs dir * } * * {@literal @}RegisterExtension * DocumentationExtension docs = * DocumentationExtension.forPath(lookUpDocsDir()); * * {@literal @}Test * void generateDocumentation() { * // use docs ... * } * }</pre> * * <h3>Registration Order</h3> * * <p>By default, if multiple extensions are registered via * {@code @RegisterExtension}, they will be ordered using an algorithm that is * deterministic but intentionally nonobvious. This ensures that subsequent runs * of a test suite execute extensions in the same order, thereby allowing for * repeatable builds. However, there are times when extensions need to be * registered in an explicit order. To achieve that, annotate each * {@code @RegisterExtension} field with {@link org.junit.jupiter.api.Order @Order}. * Any {@code @RegisterExtension} field not annotated with {@code @Order} will * appear at the end of the sorted list. * * <h3>Supported Extension APIs</h3> * * <ul> * <li>{@link ExecutionCondition}</li> * <li>{@link BeforeAllCallback}</li> * <li>{@link AfterAllCallback}</li> * <li>{@link BeforeEachCallback}</li> * <li>{@link AfterEachCallback}</li> * <li>{@link BeforeTestExecutionCallback}</li> * <li>{@link AfterTestExecutionCallback}</li> * <li>{@link TestInstancePostProcessor}</li> * <li>{@link ParameterResolver}</li> * <li>{@link TestExecutionExceptionHandler}</li> * <li>{@link TestTemplateInvocationContextProvider}</li> * </ul> * * @since 5.1 * @see ExtendWith @ExtendWith * @see Extension * @see org.junit.jupiter.api.Order @Order */
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Documented @API(status = STABLE, since = "5.1") public @interface RegisterExtension { }