Based on

  • https://sylhare.github.io/2020/07/17/Testing-with-spring-boot.html
  • https://www.baeldung.com/spring-boot-testing#unit-testing-with-webmvctest
  • https://stackoverflow.com/questions/50607285/spring-boot-testconfiguration-not-overriding-bean-during-integration-test?rq=2

I've created test example where I want to replace production bean in tests.

Production configuration requires special properties in application.yaml(for demo purpose)

package com.example.demo.app
...

@Configuration
@EnableConfigurationProperties(MyProperties::class)
open class MyConfiguration(
    private val myProperties: MyProperties
) {
    @Bean
    open fun propertiesHolder(): PropertiesHolder {
        return PropertiesHolder(arrayOf(myProperties.prop1, myProperties.prop2, myProperties.prop3))
    }
}

In tests

package com.example.demo.app
...

@TestConfiguration
open class MyConfiguration {
    @Bean
    open fun propertiesHolder(): PropertiesHolder = mockk()
}

And test looks like this:

@SpringBootTest(
    webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
    classes = [MyConfiguration::class]
)
class DemoControllerTest {
    @Autowired
    lateinit var testRestTemplate: TestRestTemplate

    @Test
    fun getItems_success() {

    }
}

This works. But if I change name of package or name of class

@TestConfiguration
    open class MyConfigurationNewName {

In both cases I see the error:

***************************
APPLICATION FAILED TO START
***************************

Description:

The bean 'propertiesHolder', defined in com.example.demo.app.MyConfigurationNewName, could not be registered. A bean with that name has already been defined in class path resource [com/example/demo/app/MyConfiguration.class] and overriding is disabled.

Action:

Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true

I also tried to use @Import annotation but result is the same:

@SpringBootTest(
    webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT
)
@Import(MyConfigurationNewName::class)

I tried to follow the error message

spring:
  main:
    allow-bean-definition-overriding: true

But another error arised after that:

***************************
APPLICATION FAILED TO START
***************************

Description:

Failed to bind properties under 'my.props' to com.example.demo.app.MyProperties:

    Reason: java.lang.NullPointerException: Parameter specified as non-null is null: method com.example.demo.app.MyProperties.<init>, parameter prop1

Action:

Update your application's configuration

I am out of ideas. Could you please help ?

The whole codebase could be found here:

https://github.com/gredwhite/springboottestconfigissue_demo

Comment From: wilkinsona

You have two classes named com.example.demo.app.MyConfiguration. One in src/main/kotlin and the other in src/test/kotlin. The class in your test source set is "hiding" the class in your main source set. This means that @EnableConfigurationProperties(MyProperties::class) that only appears on the main class is lost.

You should use differently named classes and beans and use @Primary to give priority to your test PropertiesHolder.

If you have any further questions, please follow up on Stack Overflow or Gitter. As mentioned in the guidelines for contributing, we prefer to use GitHub issues only for bugs and enhancements.

Comment From: gredwhite

You have two classes named com.example.demo.app.MyConfiguration. One in src/main/kotlin and the other in src/test/kotlin. The class in your test source set is "hiding" the class in your main source set. This means that @EnableConfigurationProperties(MyProperties::class) that only appears on the main class is lost.

You should use differently named classes and beans and use @Primary to give priority to your test PropertiesHolder.

If you have any further questions, please follow up on Stack Overflow or Gitter. As mentioned in the guidelines for contributing, we prefer to use GitHub issues only for bugs and enhancements.

Looks like you missed the main part of my question.

  1. I tried to change names and result is described in the question
  2. I just tried to add @Primary like this:
@TestConfiguration
open class MyConfigurationTest {
    @Bean
    @Primary
    open fun propertiesHolder(): PropertiesHolder = mockk()
}

But I see the eror:

***************************
APPLICATION FAILED TO START
***************************

Description:

Failed to bind properties under 'my.props' to com.example.demo.app.MyProperties:

    Reason: java.lang.NullPointerException: Parameter specified as non-null is null: method com.example.demo.app.MyProperties.<init>, parameter prop1

Action:

Update your application's configuration

  1. Topic on stackoverflow: https://stackoverflow.com/questions/77202781/testconfiguration-annotation-doesnt-override-bean-from-production-configuratio

  2. Branch with issue is https://github.com/gredwhite/springboottestconfigissue_demo/tree/bug/config_issue

Comment From: gredwhite

@wilkinsona any ideas ?