首页 > 解决方案 > @MockBean 似乎重新运行上下文创建并在 Migrate.sql 之后失败

问题描述

我有两个集成测试类。其中一个类依赖于与外部服务对话的 bean,所以我需要模拟这个 bean,并且@MockBean看起来非常适合这个。为了将一些种子注入数据库,我使用flyway的是afterMigrate.sql. 所以这里很热,它看起来像:

@RunWith(SpringRunner.class)
@ActiveProfiles("test")
@SpringBootTest
@Transactional
@Rollback
class FooTest {

  @Autowired
  private MyService myService;
}

@RunWith(SpringRunner.class)
@ActiveProfiles("test")
@SpringBootTest
@Transactional
@Rollback
class BarTest {

  @MockBean
  private ExternalService;

  @Autowired
  private MyService myService;
}

并且afterMigrate.sql

INSERT INTO my_table (id, name) VALUES (1, 'John Doe')

当我注释 as now 运行两次并且我收到错误时,问题ExternatService出现@MockBeanafretMigrate.sql

java.lang.IllegalStateException: Failed to load ApplicationContext
....
Message    : ERROR: duplicate key value violates unique constraint "my_table_pkey"

当我更改为时@MockBean@Autowired错误消失了,并且创建了上下文没有任何问题。BarTest此外,如果我单独运行,测试运行没有问题。@MockBean正如文档所说,这不是预期的行为:

在上下文中定义的任何现有的相同类型的单个 bean 都将被模拟替换。如果没有定义现有的 bean,将添加一个新的。将不会找到应用程序上下文已知但不是 bean 的依赖项(例如直接注册的那些),并且模拟 bean 将与现有依赖项一起添加到上下文中。

它并没有说将重新创建上下文。

标签: javaspringmockitoflywayspring-test

解决方案


因为当您使用@MockBean注释时,将为每个测试加载您的上下文。请参考这个 github 问题。此页面的引文:

Spring 测试框架将在测试运行之间尽可能缓存一个 ApplicationContext。为了被缓存,上下文必须具有完全相同的配置。每当您使用@MockBean 时,根据定义,您都在更改上下文配置。

因此,当您在不同的测试中使用模拟 bean 时 - 每次都会为您的测试类重新创建上下文。因此,例如,如果您有一些在创建上下文时将数据加载到 DB 的 bean——例如用于 flyway 的 bean——它们将在每次重新创建上下文时创建。


推荐阅读