Issue
I'm trying to test a class that has the @ConfigurationProperties
annotation but without loading the entire Spring context. I tried using only the JUnit5's features in order to do that but until now didn't succeed in that.
I'm using spring-boot-starter-parent
v2.6.2 .
The class I'm testing :
@ConfigurationProperties("db.mongo")
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
public class MongoProperties {
private String host;
private String db;
private String user;
private String password;
}
The application.yaml :
db:
mongo:
host: localhost
db: test
user: test-user
password: secret
My Test class :
@ExtendWith(SpringExtension.class)
@EnableConfigurationProperties({MongoProperties.class})
public class MongoPropertiesTest {
@Autowired
private MongoProperties properties;
@Test
public void mongoPropertiesLoadedTest(){
assertNotNull(properties.getDb());
assertNotNull(properties.getHost());
assertNotNull(properties.getPassword());
assertNotNull(properties.getUser());
}
}
The MongoProperties
bean is injected successfully, but all the values inside are null and the asserts fail.
Adding the @SpringBootTest
solves the issue of the null values in the instance of the bean, but it also starts the whole spring context which is what I don't want.
Solution
But using @ExtendWith(SpringExtension.class)
will also start the spring context. The difference is that it starts the context in a traditional way but @SpringBootTest
starts it in a spring-boot way. So no matter you use which of them , it still requires to start the spring context.
If your concern is to minimise the number of beans required to be loaded into the spring context when using @SpringBootTest
, you can actually configure a specified @Configuration
like the following as by default @SpringBootTest
will load all beans defined in your applications which may be too much for testing (see this for details) :
@SpringBootTest
public class MongoPropertiesTest {
@Autowired
private MongoProperties properties;
@Configuration
@EnableConfigurationProperties({MongoProperties.class})
public static class Config {
}
}
If you really want to just use @ExtendWith(SpringExtension.class)
, you will lose the spring-boot feature such as externalising configuration features which cause you cannot load properties from application.properties
and cannot support loading properties from YAML
file etc. You have to manually configure ConfigDataApplicationContextInitializer
to enable such features :
@ExtendWith(SpringExtension.class)
@ContextConfiguration(initializers = ConfigDataApplicationContextInitializer.class)
public class MongoPropertiesTest {
@Autowired
private MongoProperties properties;
@Configuration
@EnableConfigurationProperties({MongoProperties.class})
public static class Config {
}
}
You can consider to further use @SpringJUnitConfig
to combine @ExtendWith(SpringExtension.class)
and @ContextConfiguration
together which gives you :
@SpringJUnitConfig(initializers = ConfigDataApplicationContextInitializer.class)
public class MongoPropertiesTest {
@Autowired
private MongoProperties properties;
@Configuration
@EnableConfigurationProperties({MongoProperties.class})
public static class Config {
}
}
Actually both approaches do not have much differences in term of speed , so I prefer to just use @SpringBootTest
for simplicity as it does not requires you to configure ConfigDataApplicationContextInitializer
.
Answered By - Ken Chan
Answer Checked By - Terry (JavaFixing Volunteer)