Crispy
Crispy

Reputation: 3

How can I test Properties class without @SpringBootTest

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.

Upvotes: 0

Views: 50

Answers (1)

Roar S.
Roar S.

Reputation: 11134

@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()
    }
}

Upvotes: 0

Related Questions