spring-bootkotlinjunit5spring-annotationsjunit-jupiter

Spring Boot jupiter annotation custom extension configuration not working


I have configured a custom annotation:

@Target(allowedTargets = [AnnotationTarget.TYPE, AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.CLASS])
@Retention(AnnotationRetention.RUNTIME)
@ExtendWith(value = [SpringExtension::class, BuilderTestExtension::class])
@ContextConfiguration(classes = [TestConfig::class])
@SpringBootTest
annotation class BuilderTest

and also I have configured the TestConfig:

@ContextConfiguration
@ComponentScan(
    basePackages = ["com.example.api.base.builder"]
)
class TestConfig

the BuilderHelper is defined as such where ResponseBuilder class is defined in com.example.api.base.builder package:

@Service
class BuilderHelper(@Autowired var responseBuilder: ResponseBuilder)

everything works fine so far. When I try though to create another annotation for serialization tests such as:

@Target(allowedTargets = [AnnotationTarget.TYPE, AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.CLASS])
@Retention(AnnotationRetention.RUNTIME)
@ExtendWith(value = [SpringExtension::class, SerializationTestExtension::class])
@ContextConfiguration(classes = [SerializationConfig::class])
@SpringBootTest
annotation class SerializationTest

Serialization config file is defined:

@ContextConfiguration
@ComponentScan(
    basePackageClasses = [ObjectMapper::class]
)
class SerializationConfig

and SerializationHelper where ObjectMapper class is an external library with package name com.fasterxml.jackson.databind:

@Service
class SerializationHelper(@Autowired var objectMapper: ObjectMapper)

Now my error:

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.fasterxml.jackson.databind.ObjectMapper' available: expected at least 1 bean which qualifies as autowire candidate

which I assume is because of the configuration. Somehow I want to make those 2 annotations or extensions independent. Any ideas?


Solution

  • I think what you are trying to do is a little bit overcomplicated.

    You can make use of @TestConfiguration annotation in order to completely isolate your testContext from applicationContext.

    Reference: TestConfiguration

    What I suggest that you can do is this:

    Modify your @BuilderTest annotation as such:

    @Target(allowedTargets = [AnnotationTarget.TYPE, AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.CLASS])
    @Retention(AnnotationRetention.RUNTIME)
    @Import(TestConfig::class)
    @ExtendWith(SpringExtension::class)
    annotation class BuilderTest
    

    as you can see the @SpringBootTest annotation is missing so that you can isolate the context for test classes specifically. Furthermore you no longer need @ContextConfiguration annotation.

    Modify your TestConfig as such:

    @TestConfiguration
    class TestConfig {
    
        @Bean
        fun responseBuilder(): ResponseBuilder {
            // return the instance of ResponseBuilder class here
        }
    }
    

    Then in your test class you can simply do this:

    @BuilderTest
    class ResponseBuilderTest {
    
        @Autowired
        lateinit var responseBuilder: ResponseBuilder
    
        @Test
        fun testResponseBuilder() {
            //  your test logic goes here
        }
    }
    

    you can follow this procedure and do the same for @SerializationTest by creating an additional Configuration class using the @TestConfiguration annotation and providing the instance for ObjectMapper.