Mockito测试调用转抽象执行器:遗留Hazelcast监听器代码测试咨询
针对不可修改Hazelcast监听器类的测试方案(遗留代码场景)
我来分享一下针对这种遗留Hazelcast监听器类的测试方案,完全不用修改原代码就能完成验证:
首先明确你的场景:你正在维护一段遗留代码,重构前不能修改任何代码;这段代码是基于Spring+Hazelcast实现的EntryAddedListener监听器,因为要实现接口方法,所以没法修改方法签名。原类的核心代码大概是这样的:
@Component public class MyClass implements EntryAddedListener<String, MyEntry> { @Autowired @Qualifier("asyncExecutor") private Executor executor; @Autowired private ClassToBeCalled classToBeCalled; @Override public void entryAdded(EntryEvent<String, MyEntry> event) { // 遗留业务逻辑,无法修改 executor.execute(() -> { classToBeCalled.process(event.getValue()); }); } }
核心测试思路
既然不能改原代码,我们就用依赖模拟+Spring测试框架的方式,把监听器的依赖都换成模拟对象,以此隔离外部依赖,验证监听器的逻辑是否符合预期。
具体实现步骤
这里用Spring Boot Test结合Mockito来做测试,如果你用的是传统Spring项目,调整下测试注解即可:
@SpringBootTest @ExtendWith(MockitoExtension.class) public class MyClassTest { // 测试目标类,用@InjectMocks自动注入模拟依赖 @InjectMocks private MyClass myClass; // 模拟asyncExecutor,注意要加上@Qualifier匹配原类的注入限定符 @Mock @Qualifier("asyncExecutor") private Executor asyncExecutor; // 模拟业务依赖类 @Mock private ClassToBeCalled classToBeCalled; @Test public void testEntryAdded_ShouldTriggerBusinessLogic() { // 1. 构造测试用的模拟数据 MyEntry testEntry = new MyEntry(); // 模拟Hazelcast的EntryEvent,让它返回我们的测试对象 EntryEvent<String, MyEntry> mockEvent = Mockito.mock(EntryEvent.class); Mockito.when(mockEvent.getValue()).thenReturn(testEntry); // 2. 调用监听器的接口方法 myClass.entryAdded(mockEvent); // 3. 验证Executor是否收到了异步任务 Mockito.verify(asyncExecutor).execute(Mockito.any(Runnable.class)); // 4. 捕获异步任务并手动执行,验证后续业务逻辑 ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class); Mockito.verify(asyncExecutor).execute(runnableCaptor.capture()); // 手动执行Runnable,因为原代码是异步的,测试时不会自动触发 runnableCaptor.getValue().run(); // 5. 最终验证业务方法是否被正确调用 Mockito.verify(classToBeCalled).process(testEntry); } }
几个关键细节解释
- @InjectMocks:帮我们自动把标记了@Mock的依赖注入到
MyClass里,不用手动写构造器或者setter,完全不碰原代码。 - 模拟EntryEvent:Hazelcast的
EntryEvent是框架类,我们不需要真实实例,用Mockito模拟就能满足测试需求。 - 异步任务的验证:因为原代码用了
Executor异步执行业务逻辑,测试时不会自动等待任务完成,所以我们要捕获提交的Runnable并手动执行,才能验证后续的业务方法调用。 - @Qualifier匹配:原类里的
Executor用了@Qualifier("asyncExecutor"),所以模拟的时候也要加上这个注解,避免Spring注入混淆。
传统Spring项目的适配
如果你不是Spring Boot项目,只需要把测试类的注解换成:
@RunWith(SpringRunner.class) @ContextConfiguration(classes = {你的测试配置类.class}) @ExtendWith(MockitoExtension.class)
其他逻辑完全一样。
内容的提问来源于stack exchange,提问作者marco
相关产品推荐
相关产品推荐

