Spring Data JPA测试@BeforeAll报无事务EntityManager异常解决
问题原因
@DataJpaTest默认的事务生命周期绑定到单个测试方法:每个测试方法执行前才会创建关联TestEntityManager的事务,方法执行完自动回滚。@BeforeAll是类级别的执行钩子,触发时机早于所有测试方法的事务创建,哪怕你在初始化方法上加@Transactional,这个独立的事务也不会和测试框架管理的TestEntityManager持久化上下文绑定,因此抛出No transactional EntityManager found异常。
换成@BeforeEach能正常运行,是因为@BeforeEach在每个测试方法的事务创建完成后才执行,能拿到绑定好事务的EntityManager,但确实会重复插入相同测试数据,执行效率低。
修复方案
方案1:@BeforeAll内手动管理事务(改动最小,推荐)
不依赖测试框架自动创建的方法级事务,直接通过TestEntityManager手动控制事务完成初始化,初始化的数据提交后对所有后续测试方法可见:
@DataJpaTest @TestInstance(TestInstance.Lifecycle.PER_CLASS) @ActiveProfiles("testing") class RepositoryTest { @Autowired lateinit var entityManager: TestEntityManager val data = Data(...) @BeforeAll fun setup() { // 手动开启事务 entityManager.transaction.begin() entityManager.persist(data) entityManager.flush() // 提交事务,持久化测试基础数据 entityManager.transaction.commit() } @Test fun someTest() { // 测试逻辑可直接读取到初始化的data assertEquals(1,1) } }
如果需要避免测试方法修改数据互相干扰,给单个测试方法加上@Transactional注解即可,测试方法执行完会自动回滚对数据的修改,不会破坏初始化的基础数据集。
方案2:配置类级别测试事务
在测试类上添加@Transactional注解,将整个测试类的生命周期绑定到同一个事务中,此时@BeforeAll执行时就能拿到关联事务的EntityManager:
@DataJpaTest @TestInstance(TestInstance.Lifecycle.PER_CLASS) @ActiveProfiles("testing") @Transactional // 类级别事务,整个测试类运行期间共享同一个事务 class RepositoryTest { // 其余代码不变 }
这个方案的缺点是所有测试方法共享同一个持久化上下文和事务,测试方法对数据的修改会直接影响后续测试,隔离性较差,适合测试逻辑不会修改基础数据的场景。
内容的提问来源于stack exchange,提问作者user15941734
相关产品推荐
相关产品推荐

