Providing Invocation Contexts for Class Templates

A @ClassTemplate class can only be executed when at least one ClassTemplateInvocationContextProvider is registered. Each such provider is responsible for providing a Stream of ClassTemplateInvocationContext 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 @ClassTemplate.

The following example shows how to write a class template as well as how to register and implement a ClassTemplateInvocationContextProvider.

A class template with accompanying extension

@ClassTemplate
@ExtendWith(ClassTemplateDemo.MyClassTemplateInvocationContextProvider.class)
class ClassTemplateDemo {

    static final List<String> WELL_KNOWN_FRUITS
        = List.of("apple", "banana", "lemon");

    private String fruit;

    @Test
    void notNull() {
        assertNotNull(fruit);
    }

    @Test
    void wellKnown() {
        assertTrue(WELL_KNOWN_FRUITS.contains(fruit));
    }

    public class MyClassTemplateInvocationContextProvider
            implements ClassTemplateInvocationContextProvider {

        @Override
        public boolean supportsClassTemplate(ExtensionContext context) {
            return true;
        }

        @Override
        public Stream<ClassTemplateInvocationContext>
                provideClassTemplateInvocationContexts(ExtensionContext context) {

            return Stream.of(invocationContext("apple"), invocationContext("banana"));
        }

        private ClassTemplateInvocationContext invocationContext(String parameter) {
            return new ClassTemplateInvocationContext() {
                @Override
                public String getDisplayName(int invocationIndex) {
                    return parameter;
                }

                @Override
                public List<Extension> getAdditionalExtensions() {
                    return List.of(new TestInstancePostProcessor() {
                        @Override
                        public void postProcessTestInstance(
                                Object testInstance, ExtensionContext context) {
                            ((ClassTemplateDemo) testInstance).fruit = parameter;
                        }
                    });
                }
            };
        }
    }
}

In this example, the class template will be invoked twice, meaning all test methods in the class template will be executed twice. The display names of the invocations will be apple and banana as specified by the invocation context. Each invocation registers a custom TestInstancePostProcessor which is used to inject a value into a field. The output when using the ConsoleLauncher is as follows.

└─ ClassTemplateDemo ✔
   ├─ apple ✔
   │  ├─ notNull() ✔
   │  └─ wellKnown() ✔
   └─ banana ✔
      ├─ notNull() ✔
      └─ wellKnown() ✔

The ClassTemplateInvocationContextProvider extension API is primarily intended for implementing different kinds of tests that rely on repetitive invocation of all test methods in a test class 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 Parameterized Classes which uses this extension point to provide its functionality.