You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:21:44