使用Mockito编写JUnit测试,覆盖私有方法内的afterCompletion逻辑
测试覆盖TransactionSynchronizationAdapter的afterCompletion方法
方案一:借助Spring事务测试上下文触发回调
TransactionSynchronizationManager注册的同步器,只有在**事务完成(提交/回滚)**时才会自动调用afterCompletion。可以在测试中模拟事务环境,手动控制事务生命周期来触发回调:
- 给测试方法添加
@Transactional注解,确保运行在事务上下文内 - 调用触发
addTransactionLifeCycleMethods的公共方法,完成同步器注册 - 事务完成时(测试框架默认回滚或手动提交),同步器的
afterCompletion会自动执行
示例代码:
@SpringBootTest @Transactional class YourServiceTest { @Autowired private YourService targetService; @Test void testAfterCompletion() { // 准备测试参数 Map<Integer, ForecastRunDTO> newRunDTOs = new HashMap<>(); Boolean isSystemTriggered = true; // 调用目标方法,完成同步器注册 targetService.publicMethodCallingAddLifeCycle(newRunDTOs, isSystemTriggered); // 无需额外操作,测试结束时事务回滚会自动触发afterCompletion // 验证内部逻辑的执行结果即可(比如检查方法调用、状态变更等) } }
方案二:反射获取注册的同步器,手动调用方法
如果不想依赖Spring事务上下文,可以通过反射获取TransactionSynchronizationManager中已注册的同步器列表,直接调用afterCompletion:
示例代码:
class YourServiceTest { @Test void testAfterCompletionWithReflection() throws NoSuchFieldException, IllegalAccessException { // 准备测试参数 Map<Integer, ForecastRunDTO> newRunDTOs = new HashMap<>(); Boolean isSystemTriggered = true; YourService targetService = new YourService(); // 调用目标方法注册同步器 targetService.publicMethodCallingAddLifeCycle(newRunDTOs, isSystemTriggered); // 反射获取TransactionSynchronizationManager中的同步器集合 Field syncField = TransactionSynchronizationManager.class.getDeclaredField("synchronizations"); syncField.setAccessible(true); List<TransactionSynchronization> syncList = (List<TransactionSynchronization>) syncField.get(null); // 找到目标同步器并手动调用afterCompletion for (TransactionSynchronization sync : syncList) { if (sync instanceof TransactionSynchronizationAdapter) { sync.afterCompletion(TransactionSynchronization.STATUS_COMMITTED); // 验证内部逻辑执行结果 break; } } } }
方案三:重构代码,抽离同步器为独立类
如果允许修改业务代码,最优雅的方式是将匿名内部类抽成独立的同步器类,这样测试时可以直接实例化并调用目标方法:
重构后的业务代码:
private void addTransactionLifeCycleMethods(Map<Integer, ForecastRunDTO> newRunDTOs, Boolean isSystemTriggeredActualComputation) { TransactionSynchronization sync = new CustomForecastSync(newRunDTOs, isSystemTriggeredActualComputation); TransactionSynchronizationManager.registerSynchronization(sync); } // 独立的同步器类 static class CustomForecastSync extends TransactionSynchronizationAdapter { private final Map<Integer, ForecastRunDTO> newRunDTOs; private final Boolean isSystemTriggered; public CustomForecastSync(Map<Integer, ForecastRunDTO> newRunDTOs, Boolean isSystemTriggered) { this.newRunDTOs = newRunDTOs; this.isSystemTriggered = isSystemTriggered; } @Override public void afterCompletion(int status) { // 原有的业务逻辑 } }
对应的测试代码:
@Test void testSyncAfterCompletion() { Map<Integer, ForecastRunDTO> newRunDTOs = new HashMap<>(); Boolean isSystemTriggered = true; CustomForecastSync sync = new YourService.CustomForecastSync(newRunDTOs, isSystemTriggered); sync.afterCompletion(TransactionSynchronization.STATUS_ROLLED_BACK); // 验证内部逻辑的执行结果 }
内容的提问来源于stack exchange,提问作者Soumya Khanda
相关产品推荐
相关产品推荐

