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.
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.