5.12. Providing Invocation Contexts for Test Templates

A [@TestTemplate](https://junit.org/junit5/docs/current/api/org.junit.jupiter.api/org/junit/jupiter/api/TestTemplate.html) method can only be executed when at least one [TestTemplateInvocationContextProvider](https://junit.org/junit5/docs/current/api/org.junit.jupiter.api/org/junit/jupiter/api/extension/TestTemplateInvocationContextProvider.html) is registered. Each such provider is responsible for providing a Stream of [TestTemplateInvocationContext](https://junit.org/junit5/docs/current/api/org.junit.jupiter.api/org/junit/jupiter/api/extension/TestTemplateInvocationContext.html) instances. Each context may specify a custom display name and a list of additional extensions that will only be used for the next invocation of the [@TestTemplate](https://junit.org/junit5/docs/current/api/org.junit.jupiter.api/org/junit/jupiter/api/TestTemplate.html) method.

The following example shows how to write a test template as well as how to register and implement a [TestTemplateInvocationContextProvider](https://junit.org/junit5/docs/current/api/org.junit.jupiter.api/org/junit/jupiter/api/extension/TestTemplateInvocationContextProvider.html).

A test template with accompanying extension

  1. final List<String> fruits = Arrays.asList("apple", "banana", "lemon");
  2. @TestTemplate
  3. @ExtendWith(MyTestTemplateInvocationContextProvider.class)
  4. void testTemplate(String fruit) {
  5. assertTrue(fruits.contains(fruit));
  6. }
  7. public class MyTestTemplateInvocationContextProvider
  8. implements TestTemplateInvocationContextProvider {
  9. @Override
  10. public boolean supportsTestTemplate(ExtensionContext context) {
  11. return true;
  12. }
  13. @Override
  14. public Stream<TestTemplateInvocationContext> provideTestTemplateInvocationContexts(
  15. ExtensionContext context) {
  16. return Stream.of(invocationContext("apple"), invocationContext("banana"));
  17. }
  18. private TestTemplateInvocationContext invocationContext(String parameter) {
  19. return new TestTemplateInvocationContext() {
  20. @Override
  21. public String getDisplayName(int invocationIndex) {
  22. return parameter;
  23. }
  24. @Override
  25. public List<Extension> getAdditionalExtensions() {
  26. return Collections.singletonList(new ParameterResolver() {
  27. @Override
  28. public boolean supportsParameter(ParameterContext parameterContext,
  29. ExtensionContext extensionContext) {
  30. return parameterContext.getParameter().getType().equals(String.class);
  31. }
  32. @Override
  33. public Object resolveParameter(ParameterContext parameterContext,
  34. ExtensionContext extensionContext) {
  35. return parameter;
  36. }
  37. });
  38. }
  39. };
  40. }
  41. }

In this example, the test template will be invoked twice. The display names of the invocations will be apple and banana as specified by the invocation context. Each invocation registers a custom [ParameterResolver](https://junit.org/junit5/docs/current/api/org.junit.jupiter.api/org/junit/jupiter/api/extension/ParameterResolver.html) which is used to resolve the method parameter. The output when using the ConsoleLauncher is as follows.

  1. └─ testTemplate(String)
  2. ├─ apple
  3. └─ banana

The [TestTemplateInvocationContextProvider](https://junit.org/junit5/docs/current/api/org.junit.jupiter.api/org/junit/jupiter/api/extension/TestTemplateInvocationContextProvider.html) extension API is primarily intended for implementing different kinds of tests that rely on repetitive invocation of a test-like method albeit in different contexts — for example, with different parameters, by preparing the test class instance differently, or multiple times without modifying the context. Please refer to the implementations of Repeated Tests or Parameterized Tests which use this extension point to provide their functionality.