Class Extension_MatsAnnotatedClass

  • All Implemented Interfaces:
    org.junit.jupiter.api.extension.AfterEachCallback, org.junit.jupiter.api.extension.BeforeEachCallback, org.junit.jupiter.api.extension.Extension

    public final class Extension_MatsAnnotatedClass
    extends io.mats3.test.abstractunit.AbstractMatsAnnotatedClass
    implements org.junit.jupiter.api.extension.BeforeEachCallback, org.junit.jupiter.api.extension.AfterEachCallback
    Helper class to test Mats3 Endpoints which are defined using the Mats3 SpringConfig annotations, but without using the full Spring harness for testing. That is, you write tests in a "pure Java" style, but can still test your Mats3 SpringConfig annotation defined Mats endpoints. This can be terser and faster than using the full Spring test harness.

    By having at least one such test per SpringConfig defined Mats3 endpoints, you ensure an integration test of the SpringConfig aspects of your Mats endpoints: The annotations are read, the endpoint is set up, and the STOs (state) and DTOs (data) can be instantiated and serialized. For corner case unit testing where you want lots of tests, you can instead invoke the individual methods directly on the instantiated endpoint class, thus getting the fastests speeds.

    The solution creates a Spring context internally to initialize the Mats endpoints, but this should be viewed as an implementation detail, and the Spring context is not made available for the test - the specified SpringConfig annotated endpoints just turns up in the MatsFactory so that you can test it using e.g. the MatsFuturizer. The Spring context is created anew for each test, and is not shared between tests. Endpoints specified at the Extension's field init will be registered anew on the provided MatsFactory for each test method. All Endpoints are deleted after the test method has run. (The supplied MatsFactory and its underlying MQ Broker is shared between all tests.)

    "Field beans" dependency injection and dependency overriding: Fields in the test class are read out, and entered as beans into the Spring context, thus made available for injection into the Mats annotated classes when using the withAnnotatedMatsClasses(Class...) method. Overriding: When using Jupiter's @Nested feature, you may override fields from the outer test class by declaring a field with the same type in the inner @Nested test class. There is no support for qualifiers, so if your Mats-annotated endpoints require multiple beans of the same type (made unique by qualifiers), you will have to use a full Spring setup for your tests.

    MatsFactory qualifiers: If the Mats annotated endpoints has qualifiers for the MatsFactory, these will be ignored. For the same reason, any duplicate endpointIds will be ignored, and only one instance will be registered: The reason for using qualifiers are that you have multiple MatsFactories in the application, and some endpoints might be registered on multiple MatsFactories (repeating the annotation with the same endpointId, but with different qualifier). For the testing scenario using this class, we only have one MatsFactory, which will be used for all endpoints, and duplicates will thus have to be ignored. If this is a problem, you will have to use a full Spring setup for your tests.

    Classes with SpringConfig Mats3 Endpoints can either be registered using the withAnnotatedMatsClasses(Class...) method, or by using the withAnnotatedMatsInstances(Object...) method. This can both be done at the field initialization of the Extension, or inside the test method.

    The classes-variant is intended to be used on creation of the Extension, i.e. at the field initialization point - but can also be used inside the test method. Technically, it will register the class in a Spring context, and put all the fields of the test class as beans available for injection on that class - that is, dependencies in the Mats3 annotated classes will be resolved using the fields of the test class. It is important that fields are initialized before this extension runs, if there are dependencies in the test class needed by the Mats annotated class. When using Mockito and the @Mock annotation, this is resolved automatically, since Mockito will initialize the fields before the Extension is created. Mockito is started as normal, by annotating the test class with @ExtendWith(MockitoExtension.class).

    The instances-variant registers the Mats annotated class as an Endpoint when called. You will then have to initialize the class yourself, before registering it, probably using the constructor used when Spring otherwise would constructor-inject the instance. This is relevant if you only have a few tests that need the endpoint, and possibly other tests that are unit testing by calling directly on an instance of the class (i.e. calling directly on the @MatsMapping or @Stage methods).

    There are multiple examples in the test classes.

    • Field Summary

      • Fields inherited from class io.mats3.test.abstractunit.AbstractMatsAnnotatedClass

        _matsFactory, LOG_PREFIX
    • Method Detail

      • create

        public static Extension_MatsAnnotatedClass create​(io.mats3.MatsFactory matsFactory)
        Create a new instance based on the supplied MatsFactory instance.
        Parameters:
        matsFactory - MatsFactory on which to register Mats endpoints for each test.
        Returns:
        a new Extension_MatsAnnotatedClass
      • withAnnotatedMatsClasses

        public Extension_MatsAnnotatedClass withAnnotatedMatsClasses​(java.lang.Class<?>... annotatedMatsClasses)
        Add classes to act as a source for annotations to register Mats endpoints for each test.
      • withAnnotatedMatsInstances

        public Extension_MatsAnnotatedClass withAnnotatedMatsInstances​(java.lang.Object... annotatedMatsInstances)
        Add instances of classes annotated with Mats annotations to register Mats endpoints for each test.
      • beforeEach

        public void beforeEach​(org.junit.jupiter.api.extension.ExtensionContext extensionContext)
        Specified by:
        beforeEach in interface org.junit.jupiter.api.extension.BeforeEachCallback
      • afterEach

        public void afterEach​(org.junit.jupiter.api.extension.ExtensionContext context)
        Specified by:
        afterEach in interface org.junit.jupiter.api.extension.AfterEachCallback