【问题标题】:Spring Boot: @TestConfiguration Not Overriding Bean During Integration TestSpring Boot:@TestConfiguration 在集成测试期间不覆盖 Bean
【发布时间】:2018-11-09 11:06:01
【问题描述】:

我在一个用@Configuration 装饰的类中定义了一个Bean

@Configuration
public class MyBeanConfig {
    @Bean
    public String configPath() {
        return "../production/environment/path";
    }
}

我有一个用@TestConfiguration 装饰的类,它应该覆盖这个Bean

@TestConfiguration
public class MyTestConfiguration {
    @Bean
    @Primary
    public String configPath() {
        return "/test/environment/path";
    }
}

configPath bean 用于设置外部文件的路径,该文件包含在启动期间必须读取的注册码。它用于@Component 类中:

@Component
public class MyParsingComponent {
    private String CONFIG_PATH;
    
    @Autowired
    public void setCONFIG_PATH(String configPath) {
        this.CONFIG_PATH = configPath;
    }
}

在尝试调试时,我在每个方法以及测试配置类的构造函数中设置了一个断点。 @TestConfiguration 的构造函数断点被命中,所以我知道我的测试配置类实例化了,但是该类的 configPath 方法永远不会被命中。相反,普通@Configuration 类的configPath 方法被命中,MyParsingComponent 中的@Autowired String 始终是../production/environment/path,而不是预期的/test/environment/path

不知道为什么会这样。任何想法将不胜感激。

【问题讨论】:

  • 你的测试类是否用@Import(MyTestConfiguration.class)注解?
  • @SamBrannen 它不存在。并且添加它不起作用。但是将其更改为@ContextConfiguration(MyTestConfiguration.class) 确实如此。不过,仍然不明白为什么在没有 ContextConfiguration 的情况下会忽略 @Primary 注释。
  • 如 Spring Boot 参考手册中所述,任何配置在带有 @TestConfiguration 注释的顶级类中的 bean 都不会通过组件扫描被拾取。所以这就是为什么你必须明确声明它。
  • 如果用@TestConfiguration 注释的类是测试类中的静态嵌套类,它将被自动使用。
  • 如果这回答了您的问题,我可以将其作为正式的答案。 ;-)

标签: java spring-boot spring-test


【解决方案1】:

如 Spring Boot 参考手册的 Detecting Test Configuration 部分所述,任何配置在带有 @TestConfiguration 注释的顶级类中的 bean 都将不会通过组件扫描被拾取。所以你必须明确注册你的@TestConfiguration 类。

您可以通过 @Import(MyTestConfiguration.class)@ContextConfiguration(classes = MyTestConfiguration.class) 在您的测试课程中执行此操作。

另一方面,如果您使用 @TestConfiguration 注释的类是 static 嵌套类您的测试类中,它将自动注册。

【讨论】:

  • 我尝试使用#TestConfiguration 放置在顶级类上并使用#Import(MyTestConfiguration.class) 和不使用#TestConfiguration 但使用#Import(MyTestConfiguration.class) 进行测试。结果是平等的。是不是说#TestConfiguration没用了?
  • @TestConfiguration 仍然有用。有关详细信息,请参阅链接文档。
  • 网址已失效
  • 由于 Spring Boot 2.2 文档的更改,我修复了链接。谢谢
  • 我想为多个测试类重用@TestConfiguration,因此拥有一个所有其他人都继承的抽象测试类可能是一种选择。不幸的是,如果@TestConfiguration 在当前测试继承自的抽象类中,则不会拾取它。 @SamBrannen 是设计使然吗?如何在测试类之间共享@TestConfiguration
【解决方案2】:

确保@Bean 工厂方法的方法名称与任何现有的 bean 名称都不匹配。我对方法名称有疑问,例如 config() 或(在我的情况下) prometheusConfig() 与现有的 bean 名称冲突。 Spring 静默跳过这些工厂方法,根本不调用它们/不实例化 bean。

如果您想在测试中覆盖 bean 定义,请在 @Bean("beanName") 注释中明确使用 bean 名称作为字符串参数。

【讨论】:

  • 这是实际答案。我有一个带有 @TestConfiguration 的嵌套静态类,但它不起作用。问题是工厂方法的名称与实际的 bean 相同。
  • 在我非常特殊的情况下,我还必须添加@Primary。否则它只会抛出expected single matching bean but found 2
【解决方案3】:
  • 测试配置必须通过@Import({MyTestConfiguration.class})显式导入到测试中。
  • @Configuration@TestConfiguration 中的@Bean 方法的名称必须不同。至少它在 Spring Boot v2.2 中有所不同。
  • 还要确保 spring.main.allow-bean-definition-overriding=true 否则无法覆盖 bean。

【讨论】:

  • 您的第二个和第三个项目符号语句相互冲突 - bean 覆盖机制意味着 bean 名称确实匹配。
【解决方案4】:

对我来说,这个代码:

  @TestConfiguration // 1. necessary
  public class TestMessagesConfig {

    @Bean
    @Primary // 2. necessary
    public MessageSource testMessageSource() { // 3. different method name than in production code e.g. add test prefix

    }
  }

【讨论】:

    【解决方案5】:

    我最近遇到了一个类似的问题,并通过使用 @Primary 和 @Bean 注释我的测试 bean 来解决它。不知道为什么需要它,这似乎没有在 Spring 文档中记录。我的SpringBoot版本是2.0.3。

    【讨论】:

    • 我一直在寻找这个答案!谢谢,成功了
    【解决方案6】:

    我遇到了一个相关的问题,即使我使用的是内部静态类,我的测试 bean 也没有被注册。

    事实证明,您仍然需要将内部静态类添加到 @ContextConfiguration 类数组中,否则 @TestConfiguration 中的 bean 不会被拾取。

    public interface Foo {
        String execute();
    }
    
    public class FooService {
        private final Foo foo;
    
        FooService(Foo foo) {
            this.foo = foo;
        }
    
        public String execute() {
            return foo.execute();
        }
    }
    
    @ExtendWith(SpringExtension.class)
    @ContextConfiguration(classes = {FooService.class, FooTest.FooTestConfig.class})
    public class FooTest {
        @Autowired
        FooService fooService;
    
        @Test
        void test() {
            Assertions.assertEquals("MY_TEST_BEAN", fooService.execute());
        }
    
        @TestConfiguration
        static class FooTestConfig {
            @Bean
            public Foo getFooBean() {
                return () -> "MY_TEST_BEAN";
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-06-15
      • 2019-08-20
      • 1970-01-01
      • 1970-01-01
      • 2018-04-04
      • 2017-10-29
      • 2019-01-31
      • 2019-10-31
      相关资源
      最近更新 更多