【问题标题】:@Transactional annotation in Spring TestSpring Test中的@Transactional注解
【发布时间】:2021-02-11 21:45:41
【问题描述】:

我正在阅读有关 Spring test 的 Spring 文档:here

关于在测试中使用@Transactinoal,它说:

如果你的测试是@Transactional,它默认在每个测试方法结束时回滚事务。但是,由于将这种安排与 RANDOM_PORT 或 DEFINED_PORT 一起使用隐式提供了一个真正的 servlet 环境,HTTP 客户端和服务器在单独的线程中运行,因此在单独的事务中运行。在这种情况下,服务器上发起的任何事务都不会回滚。

我不明白在这种情况下在服务器上启动的任何事务都不会回滚。

感谢任何帮助。

【问题讨论】:

  • 一个事务只能在本地工作。如果您正在运行一个集成测试,那么您实际上是在发出一个 HTTP 请求,一个 HTTP 请求不是事务性的。
  • 你不能直接使用WebEnvironment.DEFINED_PORTWebEnvironment.RANDOM_PORT,或者使用dirties contexts
  • @Vincent C. 感谢您的回复。如果您使用此评论更新您的答案,我将不胜感激。使用DirtiesContext 会导致再次加载ApplicationContext 以进行下一个测试,即timeConsuming。在这种情况下,使用 WebEnvironment.NONE/MOCK 似乎是您提到的更好的选择。使用 NONE 或 MOCK 是否会遗漏任何内容。我知道应用程序不会在容器中运行,但它真的很痛苦吗?
  • 我认为您需要使用这两个选项之一。如果你不这样做,你很可能只需要WebEnvironment.MOCK(无论如何这是默认的,所以你可以简单地使用@SpringBootTest而不带任何参数)。

标签: java spring-transactions spring-test


【解决方案1】:

这意味着您的服务器不会回滚您的更改,因为它将在测试环境之外的另一个环境中运行。 只有您在测试环境中所做的更改才会被回滚。

例如:

@Autowired
private AnyRepository anyRepository;

@Test
@Transactional
void testSave(){
  anyRepository.save(new AnyEntity());
  // Will create an entity from your test environment
}

@Test
@Transactional
void testRead(){
  anyRepository.findAll();
  // Won't find any entities since they were rollbacked
}

相反,如果您使用 @SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT) 启动本地 Spring 实例),它将与您的单元测试环境分离,因此:

@Autowired
MockMvc mvc;

@Test
@Transactional
void testSave(){
  mvc.perform(post(/* enough to create an entity */);
  // Your server, detached from test environment, persists the entity
}

@Test
@Transactional
void testRead(){
  mvc.perform(get(/* enough to get that entity */);
  // Will get previously created entity (if testSave was run before)
}

如果你想在发送网络请求后回滚,你可以使用@DirtiesContext注解重置你的上下文,或者检查Reset database after each test on Spring without using DirtiesContext

编辑:在原始帖子上关注 cmets,不清楚您是否需要使用WebEnvironment.RANDOM_PORT 或者这是一个简单的问题。
如果您需要 WebEnvironment.RANDOM_PORT,最有可能的是,您可以简单地使用WebEnvironment.MOCK,它在与 JUnit 测试相同的环境中运行,因此实际上会回滚。

【讨论】:

  • 谢谢文森特。这实际上帮助了我。由于我正在测试集成,据称最好不要使用 MOCK,因为它不在容器中运行应用程序,因此不会发生完整的端到端测试。但是我不明白如果我使用 MOCK 而不是(例如)RANDOM_PORT,我会错过什么。换句话说,使用 RANDOM_PORT 时可能会捕获到使用 MOCK 时无法捕获的错误类型。
  • this answer 对你有帮助吗?
  • 不,它仍然没有回答哪些场景只被 RANDOM_PORT 覆盖,但不被 MOCK 覆盖。无论如何,我可能会在另一个问题中问它。
猜你喜欢
  • 2019-02-18
  • 2014-12-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-17
  • 2014-07-18
  • 2018-03-28
  • 2015-05-15
相关资源
最近更新 更多