I want to test Properties class without @SpringBootTest Annotation. But it doesn't work. How can I fix it? I'm using Kotlin, Spring Boot 2.7.18
@ActiveProfiles("test")
@ExtendWith(SpringExtension::class)
@ContextConfiguration(classes = [TestConfig::class])
class AESTest {
@Autowired
lateinit var properties: TestAESProperty
@Test
fun decrypt() {
assertEquals(properties.key, "hello")
assertEquals(properties.iv, "world")
}
}
@TestConfiguration
@EnableConfigurationProperties(TestAESProperty::class)
class TestConfig {
}
@ConstructorBinding
@ConfigurationProperties(prefix = "common.test.aes")
data class TestAESProperty(
val key: String,
val iv: String,
)
---- application-test.yml ----------
spring:
config:
activate:
on-profile: test
common:
test:
aes:
key: hello
iv: world
But, below errors accurs.
Failed to bind properties under 'common.test.aes' to TestAESProperty
Parameter specified as non-null is null: method TestAESProperty.<init>, parameter key
Error creating bean with name 'TestAESProperty'
Could not bind properties to 'TestAESProperty' : prefix=common.test.aes, ignoreInvalidFields=false, ignoreUnknownFields=true; nested exception is org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'common.test.aes' to TestAESProperty
I want to data bind from 'application-test.yml' file because it can be more secure with AWS service manager.
@ConfigurationProperties
annotated classes can be tested using ApplicationContextRunner
.
Let's annotate key
with @field:NotBlank
. Please keep in mind that this is Spring Boot 2.7.18, hence javax instead of Jakarta.
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.context.properties.ConstructorBinding
import org.springframework.validation.annotation.Validated
import javax.validation.constraints.NotBlank
@Validated
@ConstructorBinding
@ConfigurationProperties(prefix = "common.test.aes")
data class TestAESProperty(
@field:NotBlank val key: String,
val iv: String,
)
Now we can test that application context starts with valid value for key
, and fails if it's blank. Values has to be defined with .withPropertyValues
, not application-test.yml
.
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Assertions.assertEquals
import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.boot.test.context.runner.ApplicationContextRunner
import kotlin.test.Test
class AESTest {
@EnableConfigurationProperties(TestAESProperty::class)
class TestConfig
@Test
fun `context load with valid properties`() {
CONTEXT_RUNNER
.withUserConfiguration(TestConfig::class.java)
.withPropertyValues(
"common.test.aes.key=~key~",
"common.test.aes.iv=~iv~"
)
.run { context ->
assertThat(context).hasSingleBean(TestAESProperty::class.java)
val sut = context.getBean(TestAESProperty::class.java)
assertEquals("~key~", sut.key)
assertEquals("~iv~", sut.iv)
}
}
@Test
fun `context load with invalid properties`() {
CONTEXT_RUNNER
.withUserConfiguration(TestConfig::class.java)
.withPropertyValues(
"common.test.aes.key=",
"common.test.aes.iv=~iv~"
)
.run { context ->
assertThat(context).hasFailed()
}
}
companion object {
val CONTEXT_RUNNER: ApplicationContextRunner = ApplicationContextRunner()
}
}