Spring Boot单元测试中,如何在不启动整个应用程序的情况下使@Autowired生效

huangapple go评论110阅读模式
英文:

Spring Boot Unit Test with @Autowired how to get it to to work without starting entire Application

问题

我正在尝试对使用@Configuration注释的类的配置进行单元测试。该类相当简单:

  1. @Configuration
  2. @ConfigurationProperties(prefix = "feed")
  3. public class SpringNyseFeedConfig extends FeedConfig {
  4. private static final Logger LOG = LoggerFactory.getLogger(SpringNyseFeedConfig.class);
  5. public SpringNyseFeedConfig() {
  6. LOG.debug("ctor():created {}", SpringNyseFeedConfig.class);
  7. }
  8. @PostConstruct
  9. public void completeConfig() {
  10. LOG.debug("completeConfig(): validating configuration...");
  11. postConfigure().validate(); // 需要设置最终属性并验证
  12. }
  13. }

这个单元测试也很简单:

  1. @SpringBootTest
  2. @ActiveProfiles("test")
  3. public class SpringNyseFeedConfigTest {
  4. @Autowired
  5. private SpringNyseFeedConfig config;
  6. @Test
  7. void propertiesReadAsExpected() {
  8. assertNotNull(config);
  9. ServerConnection requestServer = config.getRequestServer();
  10. assertEquals("192.168.1.200", requestServer.getHost());
  11. // ...
  12. // ...
  13. }
  14. }

测试可以正确地注入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:

  1. @Configuration
  2. @ConfigurationProperties(prefix = "feed")
  3. public class SpringNyseFeedConfig extends FeedConfig {
  4. private static final Logger LOG = LoggerFactory.getLogger(SpringNyseFeedConfig.class);
  5. public SpringNyseFeedConfig() {
  6. LOG.debug("ctor():created {}", SpringNyseFeedConfig.class);
  7. }
  8. @PostConstruct
  9. public void completeConfig() {
  10. LOG.debug("completeConfig(): validating configuration...");
  11. postConfigure().validate(); // need to set final properties and validate
  12. }
  13. }

The unit test is also simple:

  1. @SpringBootTest
  2. @ActiveProfiles("test")
  3. public class SpringNyseFeedConfigTest {
  4. @Autowired
  5. private SpringNyseFeedConfig config;
  6. @Test
  7. void propertiesReadAsExpected() {
  8. assertNotNull(config);
  9. ServerConnection requestServer = config.getRequestServer();
  10. assertEquals("192.168.1.200", requestServer.getHost());
  11. ...
  12. ...
  13. }
  14. }

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

  1. 有一个专用的注解 `@TestPropertySource` 用于启用对 `ConfigurationProperties` 的测试这应该按预期工作
  2. ```java
  3. @ExtendWith(SpringExtension.class)
  4. @EnableConfigurationProperties(value = SpringNyseFeedConfig .class)
  5. @TestPropertySource("/application-test.properties")
  6. public class SpringNyseFeedConfigTest {
  7. @Autowired
  8. private SpringNyseFeedConfig config;
  9. // ...
  10. }

请注意:我故意使用属性而不是YAML文件,因为后者在测试中不能正常工作。

基于:https://www.baeldung.com/spring-boot-testing-configurationproperties

  1. <details>
  2. <summary>英文:</summary>
  3. 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 {

  1. @Autowired
  2. private SpringNyseFeedConfig config;

// ...
}

  1. Please note: I&#39;m intentionally using properties instead YAML file because the latter doesn&#39;t work properly with tests.
  2. Based on: [https://www.baeldung.com/spring-boot-testing-configurationproperties][1]
  3. [1]: https://www.baeldung.com/spring-boot-testing-configurationproperties
  4. </details>
  5. # 答案2
  6. **得分**: 1
  7. 使用`ApplicationRunner`来组装上下文。
  8. ```kotlin
  9. // kotlin 代码片段
  10. class YourTests{
  11. private val contextRunner = ApplicationContextRunner()
  12. @Test
  13. fun testAppProperties() {
  14. contextRunner
  15. .withUserConfiguration(YourConfig::class.java)
  16. .run {
  17. val bean: YourBean = it.getBean(YourBean::class.java)
  18. assertThat(bean.baseUrl).isEqualTo("http://localhost:8080")
  19. }
  20. }
  21. }

Java 版本:

  1. public class YourTests{
  2. private final ApplicationContextRunner contextRunner = new ApplicationContextRunner();
  3. @Test
  4. public void testAppProperties() {
  5. contextRunner
  6. .withUserConfiguration(YourConfig.class)
  7. .run( ctx -> {
  8. var bean = ctx.getBean(YourBean.class);
  9. assertThat(bean.baseUrl).isEqualTo("http://localhost:8080");
  10. });
  11. }
  12. }
英文:

Use ApplicationRunner to assemble the context.

  1. // kotlin code fragment
  2. class YourTests{
  3. private val contextRunner = ApplicationContextRunner()
  4. @Test
  5. fun testAppProperties() {
  6. contextRunner
  7. .withUserConfiguration(YourConfig::class.java)
  8. .run {
  9. val bean: YourBean = it.getBean(YourBean::class.java)
  10. assertThat(bean.baseUrl).isEqualTo(&quot;http://localhost:8080&quot;)
  11. }
  12. }
  13. }

Java version:

  1. public class YourTests{
  2. private final ApplicationContextRunner contextRunner = new ApplicationContextRunner();
  3. @Test
  4. public void testAppProperties() {
  5. contextRunner
  6. .withUserConfiguration(YourConfig.class)
  7. .run( ctx -&gt; {
  8. var bean = ctx.getBean(YourBean.class);
  9. assertThat(bean.baseUrl).isEqualTo(&quot;http://localhost:8080&quot;);
  10. });
  11. }
  12. }

huangapple
  • 本文由 发表于 2023年6月22日 06:08:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/76527454.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定