Spring 引导:@TestConfiguration 在集成测试期间未覆盖 Bean

Spring Boot: @TestConfiguration Not Overriding Bean During Integration Test

我在 class 中定义了一个 Bean,用 @Configuration:

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

我有一个 class 装饰着 @TestConfiguration 应该覆盖这个 Bean:

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

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

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

在尝试调试时,我在每个方法以及测试配置的构造函数中设置了一个断点class。 @TestConfiguration 的构造函数断点被命中,所以我知道我的测试配置 class 实例化了,但是 class 的 configPath 方法从未被命中。相反,正常 @Configuration class 的 configPath 方法被命中,而 MyParsingComponent 中的 @Autowired String 总是 ../production/environment/path 而不是比预期的 /test/environment/path.

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

如 Spring 引导参考手册的 Detecting Test Configuration 部分所述,在顶层 class 中配置的任何 beans 注释为 @TestConfiguration通过组件扫描被拾取。所以你必须明确注册你的 @TestConfiguration class.

您可以通过 @Import(MyTestConfiguration.class)@ContextConfiguration(classes = MyTestConfiguration.class) 在您的测试中做到这一点 class。

另一方面,如果用 @TestConfiguration 注释的 class 是 static 嵌套 class within 你的测试class,会自动注册

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

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

  • 必须通过 @Import({MyTestConfiguration.class}) 在测试中显式导入测试配置。
  • @Configuration@TestConfiguration 中的 @Bean 方法的名称必须不同。至少它在 Spring Boot v2.2 中有所不同。
  • 还要确保 spring.main.allow-bean-definition-overriding=true 否则无法覆盖 bean。

为我工作了这段代码:

  @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

    }
  }

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

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

事实证明,您仍然需要将内部静态 class 添加到 @ContextConfiguration class 数组,否则 @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";
        }
    }
}