Spring Repository:缺@Transactional时自定义删除测试通过,生产环境失效
问题原因分析
@DataJpaTest 会默认给每个测试方法自动添加 @Transactional 注解,且测试结束后自动回滚事务。这就导致:即使你的 Repository 删除方法没有标注 @Transactional,测试时整个方法都运行在测试框架提供的事务上下文里,删除操作会在事务内执行,后续查询也在同一个事务中,所以能看到删除后的状态,测试自然通过。
但生产环境中,若调用该删除方法的外层逻辑没有开启事务,且方法本身无 @Transactional,Spring Data JPA 的派生删除方法(如 deleteByXXX)会因缺少事务上下文无法提交 DML 操作,最终导致删除失效。
让测试在缺失注解时失败的方案
给目标测试方法添加 @Transactional(propagation = Propagation.NOT_SUPPORTED),强制测试方法脱离事务上下文,模拟生产环境中无事务的调用场景:
@DataJpaTest public class AlertRepositoryTest { @Autowired @Qualifier("alertRepository") private AlertRepository underTest; @AfterEach void tearDown(){ underTest.deleteAll(); } @Test @Transactional(propagation = Propagation.NOT_SUPPORTED) void testUpdateAndDelete() { Timestamp triggered = java.sql.Timestamp.valueOf("2007-09-23 10:10:10.0"); Timestamp fixed = java.sql.Timestamp.valueOf("2012-09-23 10:10:10.0"); Alert alert1 = new Alert("FIXED", "event1", 0L, 0L, triggered, fixed, "domain1", "service1", "metric1", "context1", 1L, 1L); Alert alert2 = new Alert("FIXED", "event2", 0L, 0L, triggered, fixed, "domain2", "service2", "metric2", "context2", 1L, 1L); // CrudRepository的save方法自带@Transactional,会自动提交事务,数据能正常入库 underTest.save(alert1); underTest.save(alert2); // some other assertions ... Timestamp deletion = java.sql.Timestamp.valueOf("2019-09-23 10:10:10.0"); // 此时删除方法无@Transactional,也没有外层事务,操作无法生效 underTest.deleteByStatusAndTriggeredBefore("FIXED", deletion); Page<Alert> alertReturned = underTest.findByStatus("FIXED", Pageable.unpaged()); // 断言会失败,因为数据并未被删除 assertThat(alertReturned.getContent().size()).isEqualTo(0); } }
此时如果 Repository 的删除方法未添加 @Transactional,测试会因删除操作未生效而失败,提前暴露生产环境会遇到的问题。
内容的提问来源于stack exchange,提问作者tristan19954
相关产品推荐
相关产品推荐

