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";
}
}
}
我在 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";
}
}
}