英文:
Spring Boot Unit Test with @Autowired how to get it to to work without starting entire Application
问题
我正在尝试对使用@Configuration
注释的类的配置进行单元测试。该类相当简单:
@Configuration
@ConfigurationProperties(prefix = "feed")
public class SpringNyseFeedConfig extends FeedConfig {
private static final Logger LOG = LoggerFactory.getLogger(SpringNyseFeedConfig.class);
public SpringNyseFeedConfig() {
LOG.debug("ctor():created {}", SpringNyseFeedConfig.class);
}
@PostConstruct
public void completeConfig() {
LOG.debug("completeConfig(): validating configuration...");
postConfigure().validate(); // 需要设置最终属性并验证
}
}
这个单元测试也很简单:
@SpringBootTest
@ActiveProfiles("test")
public class SpringNyseFeedConfigTest {
@Autowired
private SpringNyseFeedConfig config;
@Test
void propertiesReadAsExpected() {
assertNotNull(config);
ServerConnection requestServer = config.getRequestServer();
assertEquals("192.168.1.200", requestServer.getHost());
// ...
// ...
}
}
测试可以正确地注入config
,并配置了从application-test.yml
文件中读取的属性。
问题在于这个测试会导致Spring初始化应用程序中的所有Bean(这需要时间)。
我尝试了大约半打建议,试图限制测试仅实例化SpringNyseFeedConfig
对象,但它们都导致要么根本不注入任何东西(config
等于null
),要么注入一个未从yml
文件配置的对象(即未设置属性)。
我该如何更新单元测试,以便它将读取文件并自动配置和注入SpringNyseFeedConfig
对象,而无需实例化应用程序中的每个其他组件?
英文:
I am trying to unit test configuration of a class annotated with @Configuration
. The class is fairly simple:
@Configuration
@ConfigurationProperties(prefix = "feed")
public class SpringNyseFeedConfig extends FeedConfig {
private static final Logger LOG = LoggerFactory.getLogger(SpringNyseFeedConfig.class);
public SpringNyseFeedConfig() {
LOG.debug("ctor():created {}", SpringNyseFeedConfig.class);
}
@PostConstruct
public void completeConfig() {
LOG.debug("completeConfig(): validating configuration...");
postConfigure().validate(); // need to set final properties and validate
}
}
The unit test is also simple:
@SpringBootTest
@ActiveProfiles("test")
public class SpringNyseFeedConfigTest {
@Autowired
private SpringNyseFeedConfig config;
@Test
void propertiesReadAsExpected() {
assertNotNull(config);
ServerConnection requestServer = config.getRequestServer();
assertEquals("192.168.1.200", requestServer.getHost());
...
...
}
}
The test is getting the config
injected correctly, and configured with properties read from an application-test.yml
file.
The problem is that the test causes Spring initializes all the Beans in the application (which is time consuming).
I've tried about a half dozen suggestions to try to limit the test to only instantiating the SpringNyseFeedConfig object only, but they have all resulted in either not injecting anything at all (config == null), or injecting an object not configured from the yml
file (i.e. no properties set).
How can I update the unit test so that it will read the file and auto-configure and inject the SpringNyseFeedConfig object without instantiating every other component in the application?
答案1
得分: 1
有一个专用的注解 `@TestPropertySource` 用于启用对 `ConfigurationProperties` 的测试。这应该按预期工作:
```java
@ExtendWith(SpringExtension.class)
@EnableConfigurationProperties(value = SpringNyseFeedConfig .class)
@TestPropertySource("/application-test.properties")
public class SpringNyseFeedConfigTest {
@Autowired
private SpringNyseFeedConfig config;
// ...
}
请注意:我故意使用属性而不是YAML文件,因为后者在测试中不能正常工作。
基于:https://www.baeldung.com/spring-boot-testing-configurationproperties
<details>
<summary>英文:</summary>
There is a dedicated annotation `@TestPropertySource` to enable testing of `ConfigurationProperties`. This should work as expected:
@ExtendWith(SpringExtension.class)
@EnableConfigurationProperties(value = SpringNyseFeedConfig .class)
@TestPropertySource("/application-test.properties")
public class SpringNyseFeedConfigTest {
@Autowired
private SpringNyseFeedConfig config;
// ...
}
Please note: I'm intentionally using properties instead YAML file because the latter doesn't work properly with tests.
Based on: [https://www.baeldung.com/spring-boot-testing-configurationproperties][1]
[1]: https://www.baeldung.com/spring-boot-testing-configurationproperties
</details>
# 答案2
**得分**: 1
使用`ApplicationRunner`来组装上下文。
```kotlin
// kotlin 代码片段
class YourTests{
private val contextRunner = ApplicationContextRunner()
@Test
fun testAppProperties() {
contextRunner
.withUserConfiguration(YourConfig::class.java)
.run {
val bean: YourBean = it.getBean(YourBean::class.java)
assertThat(bean.baseUrl).isEqualTo("http://localhost:8080")
}
}
}
Java 版本:
public class YourTests{
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner();
@Test
public void testAppProperties() {
contextRunner
.withUserConfiguration(YourConfig.class)
.run( ctx -> {
var bean = ctx.getBean(YourBean.class);
assertThat(bean.baseUrl).isEqualTo("http://localhost:8080");
});
}
}
英文:
Use ApplicationRunner
to assemble the context.
// kotlin code fragment
class YourTests{
private val contextRunner = ApplicationContextRunner()
@Test
fun testAppProperties() {
contextRunner
.withUserConfiguration(YourConfig::class.java)
.run {
val bean: YourBean = it.getBean(YourBean::class.java)
assertThat(bean.baseUrl).isEqualTo("http://localhost:8080")
}
}
}
Java version:
public class YourTests{
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner();
@Test
public void testAppProperties() {
contextRunner
.withUserConfiguration(YourConfig.class)
.run( ctx -> {
var bean = ctx.getBean(YourBean.class);
assertThat(bean.baseUrl).isEqualTo("http://localhost:8080");
});
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论