As introduced before, Jupiter is the name given to the new programming model of JUnit 5, described in detail in chapter 3, JUnit 5 standard tests and chapter 4, Simplifying testing with advanced JUnit features, together with the extension model. The extension model allows to extend the Jupiter programming model with custom additions. Thanks to this, third-party frameworks (such as Spring or Mockito, to name a few) can achieve interoperability with JUnit 5 in a seamless way. The extensions provided by these frameworks will be studied in chapter 5, Integration of JUnit 5 with external frameworks. In the current section, we analyze the general performance of the extension model and also the extensions provided out of the box in JUnit 5.
In contrast to former extension points in JUnit 4 (that is, test runners and rules), the JUnit 5 extension model consists of a single, coherent concept: the Extension API. This API allows to extend the core functionality of JUnit 5 by any third party (tool vendor, developers, and so on). The first thing we need to understand about extensions in Jupiter is that each new extension implements an interface called Extension. This interface is a marker interface, that is, a Java interface with no field or methods:
package org.junit.jupiter.api.extension;
import static org.apiguardian.api.API.Status.STABLE;
import org.apiguardian.api.API;
/**
* Marker interface for all extensions.
*
* @since 5.0
*/
@API(status = STABLE, since = "5.0")
public interface Extension {
}
In order to make ease the creation of Jupiter extensions, JUnit 5 provides a set of extensions points which allows to execute custom code in different parts of the test life cycle. The following table contains a summary of the extension points in Jupiter, and its details are presented in the next sections:
Extension point |
Implemented by extensions which want to… |
TestInstancePostProcessor |
Provide additional behavior just after the test instantiation |
BeforeAllCallback |
Provide additional behavior before all tests are invoked in a test container |
BeforeEachCallback |
Provide additional behavior to tests before each test is invoked |
BeforeTestExecutionCallback |
Provide additional behavior to tests immediately before each test is executed |
TestExecutionExceptionHandler |
Handle exceptions thrown during test execution |
AfterAllCallback |
Provide additional behavior to test containers after all tests have been invoked |
AfterEachCallback |
Provide additional behavior to tests after each test has been invoked |
AfterTestExecutionCallback |
Provide additional behavior to tests immediately after each test has been executed |
ExecutionCondition |
Conditionate the test execution at runtime |
ParameterResolver |
Resolve parameters at runtime |
Once we created an extension, in order to use it, we need to use the annotation ExtendWith. This annotation can be used to register one or more extensions. It can be declared on interfaces, classes, methods, fields, and even in other annotations:
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
public class MyTest {
@ExtendWith(MyExtension.class)
@Test
public void test() {
// My test logic
}
}