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
- Spring Boot: @TestConfiguration Not Overriding Bean During Integration Test
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
Branch with issue is: https://github.com/gredwhite/springboottestconfigissue_demo/tree/bug/config_issue
P.S.
I tried spring boot versions
- 3.0.1
- 3.1.0
- 3.1.4
The problem you are having is essentially a duplicate of Override default Spring-Boot application.properties settings in Junit Test.
You have defined an
application.ymlfile atsrc/main/resourcesand also atsrc/test/resources. This means when your tests run there is only a single file available on the classpath (the one insrc/test/resources).When
MyConfigurationis processed the@EnableConfigurationProperties(MyProperties::class)annotation is respected and theMyPropertiesdata class is bound. This class requires non-null values but since your testapplication.ymlfile does not definemy.propertyvalues you get the following exception:The test passes if I update your code by renaming
src/test/resources/application.ymltosrc/test/resources/application-test.ymland addingproperties = ["spring.config.additional-location=classpath:application-test.yml"]to@SpringBootTestannotation.