Ser*_*hyr 3 java spring spring-test mockito flyway
我有两个集成测试类。其中一个类依赖于与外部服务通信的 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;
}
Run Code Online (Sandbox Code Playgroud)
并且afterMigrate.sql:
INSERT INTO my_table (id, name) VALUES (1, 'John Doe')
Run Code Online (Sandbox Code Playgroud)
当我注释的问题似乎ExternatService是@MockBean因为现在的afretMigrate.sql运行两次,我得到的错误:
java.lang.IllegalStateException: Failed to load ApplicationContext
....
Message : ERROR: duplicate key value violates unique constraint "my_table_pkey"
Run Code Online (Sandbox Code Playgroud)
当我将其更改@MockBean为@Autowired错误时,错误消失了,并且创建了上下文没有任何问题。此外,如果我BarTest单独运行,测试运行没有问题。@MockBean正如文档所说,这不是预期的行为:
上下文中定义的任何现有的相同类型的单个 bean 都将被模拟替换。如果没有定义现有 bean,则会添加一个新 bean。应用程序上下文已知但不是 bean 的依赖项(例如那些直接注册的)将不会被找到,并且一个模拟 bean 将与现有依赖项一起添加到上下文中。
它并没有说将重新创建上下文。
因为当您使用@MockBean注释时,将为每个测试加载您的上下文。请参考这个 github 问题。此页面的引文:
Spring 测试框架将在测试运行之间尽可能缓存 ApplicationContext。为了被缓存,上下文必须具有完全等效的配置。每当您使用 @MockBean 时,根据定义,您都在更改上下文配置。
因此,当您在不同的测试中使用模拟 bean 时 - 每次都会为您的测试类重新创建上下文。因此,例如,如果您有一些 bean 在创建上下文时将数据加载到 DB - 例如用于 flyway 的 bean - 它们将在每次重新创建上下文时创建。
这是我解决这个问题的方法(我认为这是一个问题)。
解决方案 1:
我创建了一个MockConfig类,应该mock为整个测试套件创建一个类:
@Configration
public class MockConfig {
@Bean
@Primary
public ExternalService externalService() {
return mock(ExternalService.class);
}
}
Run Code Online (Sandbox Code Playgroud)
在测试中,我只是自动装配外部服务:
@Autowire
private ExternalService externalService;
Run Code Online (Sandbox Code Playgroud)
但这个解决方案有一个问题,它会创建一个真实的 bean,然后用模拟 bean 覆盖它。如果您的外部服务在创建时与外部资源建立连接,而您不需要这样做,那么您将需要另一个解决方案。
解决方案 2:
创建一个基本抽象类,其中@MockBean包含:
@RunWith(SpringRunner.class)
@ActiveProfiles("test")
@SpringBootTest
@Transactional
@Rollback
public abstract class BaseIntegrationTest {
@MockBean
ExternalService externalService;
}
Run Code Online (Sandbox Code Playgroud)
并从此基类扩展集成测试:
class FooTest extends BaseIntegrationTest {
@Autowired
private MyService myService;
}
class BarTest extends BaseIntegrationTest {
@Autowired
private MyService myService;
}
Run Code Online (Sandbox Code Playgroud)
现在上下文不会刷新,因为它始终相同,并且不会创建真正的 bean。
| 归档时间: |
|
| 查看次数: |
1672 次 |
| 最近记录: |