【问题标题】:Nested configuration not working as expected嵌套配置未按预期工作
【发布时间】:2016-09-17 12:56:42
【问题描述】:

我正在使用 Spring Boot 开发一个项目,我们刚刚升级到 1.4.0.RELEASE 版本。作为版本升级的一部分,我们已经开始在抽象集成测试类上使用@SpringBootTest 注解。在阅读the documentation 之后,听起来我们应该能够使用嵌套的@TestConfiguration-annotated 配置类来覆盖特定测试期间的 bean 定义。这对我们不起作用,相反,我们试图覆盖的非测试 bean 仍在使用中。

有趣的是,模拟测试 bean 和生产 bean 的用法实际上在同一个测试中交织在一起,就好像两个 bean 在应用程序上下文中并排存在一样。此外,似乎集成测试的运行顺序会以某种方式影响这种行为。我想知道这是否是我们配置错误,或者是否还有其他原因。

编辑:

集成测试继承的抽象类如下所示:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ActiveProfiles({"local", "test"})
public abstract class BaseIntegrationTest {

    @Value("${local.server.port}")
    protected int port;
}

我们看到奇怪行为的集成测试如下所示:

public class WebhookProcessorIT extends BaseIntegrationTest {

    @TestConfiguration
    public static class Config {
        @Bean
        @Primary
        public WebhookTask webhookTask() {
            return mock(WebhookTask.class);
        }
    }

    // sometimes the mock above is used and sometimes
    // the actual production bean is used
    @Autowired
    private WebhookTask task;

    @Before
    public void setup() {
        when(task.process(any())).thenReturn(true);
    }

    // tests ...
}

这就是根应用上下文类的样子:

@EnableAutoConfiguration(exclude = ErrorMvcAutoConfiguration.class)
@SpringBootApplication
public class Application {
    private static final Logger log = LoggerFactory.getLogger(Application.class);

    public static void main(String[] args) {
        final SpringApplication app = new SpringApplication(Application.class);
        app.setBannerMode(Banner.Mode.OFF);
        app.run(args);
    }
}

编辑:

我也尝试过使用@MockBean,像这样:

public class WebhookProcessorIT extends BaseIntegrationTest {

    @MockBean
    private WebhookTask task;

但是当测试运行时我得到了相同的结果。当我在测试设置期间查看日志时,我可以看到 Spring 正在尝试使用我提供的 mock 覆盖生产 bean:

build   15-Sep-2016 09:09:24    2016-09-15 09:09:24 [34mINFO [0;39m [36m[DefaultListableBeanFactory][0;39m (main) Overriding bean definition for bean 'productionWebhookTask' with a different definition

但是,在测试执行方面,我仍然可以看到正在使用的生产 bean:

build   15-Sep-2016 09:09:29    2016-09-15 09:09:29 [39mDEBUG[0;39m [36m[WebhookSupplier][0;39m (WebhookProcessor) Received webhook with ID '1234' from queue.
build   15-Sep-2016 09:09:30    2016-09-15 09:09:30 [39mDEBUG[0;39m [36m[WebhookSupplier][0;39m (WebhookProcessor) Received webhook with ID '5678' from queue.
build   15-Sep-2016 09:09:30    2016-09-15 09:09:30 [39mDEBUG[0;39m [36m[ProductionWebhookTask][0;39m (WebhookProcessor) Received webhook with ID '1234' for processing // production webhook task bean still being used for webhook '1234'
build   15-Sep-2016 09:09:30    2016-09-15 09:09:30 [39mDEBUG[0;39m [36m[WebhookSupplier][0;39m (WebhookProcessor) Deleting webhook with id '5678' from queue. // mock bean causes production logic to be skipped and we just delete webhook '5678'
// More logs from production webhook task operating on webhook with id '1234' and causing the test to fail

【问题讨论】:

  • 你的意思是偶尔运行一个真正的bean而不是模拟的bean还是什么?
  • 您能否分享您的测试课程,以便我们了解您的具体设置的更多信息?
  • @ShadyRagab 是的,看起来是这样。
  • @enbdk 运行两个配置类会有点棘手,因为 TestConfiguration 不会替换生产类。它们都将在上下文中。
  • @enbdk 我不太了解日志行,但您是否也会提供您的方法存根和期望?

标签: spring-boot


【解决方案1】:

无论如何,您可以使用 @Profile("test") 注释您的测试 bean,并使用 @Profile("production") 注释您的真实 bean

并在您的属性文件中放入属性 spring.profiles.active=test

来自文档

与常规的@Configuration 类不同,@TestConfiguration 的使用 不会阻止@SpringBootConfiguration 的自动检测。

与嵌套的 @Configuration 类不同,后者将被用来代替 你的应用程序的主要配置,一个嵌套的@TestConfiguration 除了您的应用程序的主要类之外,还将使用类 配置。

【讨论】:

  • 我不想在这种情况下使用配置文件,因为我们有其他使用生产 WebhookTask bean 的集成测试,理想情况下我们希望能够使用嵌套配置将其存根仅用于某些测试。
  • 另外,我在我的问题中链接了文档的那一部分;)
【解决方案2】:

由于您使用 Spring Boot 1.4.0 版,您可以继续使用新引入的注解 @MockBean,而不是使用不同的配置类来模拟您的原始 bean。它直截了当,非常适合您的用例。

Here you go with an example from the documentation

【讨论】:

  • 我也尝试过使用 MockBean 注释,得到了相同的结果。我已经用一些与此相关的 cmets 再次更新了我的问题。
猜你喜欢
  • 2012-11-18
  • 1970-01-01
  • 1970-01-01
  • 2019-05-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-22
相关资源
最近更新 更多