springspring-bootunit-testingjunitconfigurationproperties

How to write Spring unit tests for classes annotated with @ConfigurationProperties?


I have a class with configuration properties and I would like to write an unit test in Spring (the application is based on Spring Boot), but I don' want to use @SpringBootTest, because the whole application context is loaded for too long.

POM dependencies:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.9</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>test-property-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>test-property-demo</name>
    <description>test-property-demo</description>
    <properties>
        <java.version>19</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>


        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

Production code:

package com.example.testpropertydemo.demo;

import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;

@Getter
@Setter
@ConfigurationProperties(prefix = "demo")
class DemoProperties {

    private String message;
}

package com.example.testpropertydemo.demo;

import lombok.AllArgsConstructor;

@AllArgsConstructor
public class DemoFacade {

    private final DemoProperties demoProperties;

    public String getHello() {
        return demoProperties.getMessage();
    }
}

package com.example.testpropertydemo.demo;

import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableConfigurationProperties(DemoProperties.class)
class DemoConfig {

    @Bean
    DemoFacade demoFacade(DemoProperties  demoProperties) {
        return new DemoFacade(demoProperties);
    }
}


Test code:

application.yml


demo:
  message: bonjour le monde

DemoFacadeTest:


@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {DemoConfig.class})
@TestPropertySource(locations = "classpath:config/application.yml")
class DemoFacadeTest {

    @Autowired
    private DemoFacade demoFacade;

    @Test
    void getHello() {
        assertEquals("bonjour le monde", demoFacade.getHello());
    }
}

The problem is I can't force the Spring to read the property file and put the properties to the instance of property configuration class in test. Beans are instantiated correctly, but the demoProperties bean is not populated with property coming from application.yml

I tried @SpringBootTest and it does work, but it is not the solution for me. Context configuration for the app is to heavy to load it in the test.

I tried several configurations of Spring annotations, but nothing worked for me.


Solution

  • You can limit the context of a springboottest by setting classes

    @SpringBootTest(classes = {DemoConfig.class})
    

    I’m not sure why you’re setting a TestPropertiesSource in a config/ path. If you place the application.yml in the resources folder under java and/or test you shouldn’t have to set that explicitly.