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 insrc/main/kotlinand the other insrc/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
@Primaryto give priority to your testPropertiesHolder.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.
- I tried to change names and result is described in the question
- 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
-
Topic on stackoverflow: https://stackoverflow.com/questions/77202781/testconfiguration-annotation-doesnt-override-bean-from-production-configuratio
-
Branch with issue is https://github.com/gredwhite/springboottestconfigissue_demo/tree/bug/config_issue
Comment From: gredwhite
@wilkinsona any ideas ?