Mockito如何验证以Callable为参数的方法及内部调用逻辑?
问题分析与解决方案
你的测试报错核心原因是:Mock的Task不会主动执行传入的Callable的call()方法,同时测试代码里调用captor.call()是错误的用法,且泛型匹配可能存在问题。下面给出两种可行的解决方案:
方案一:修正ArgumentCaptor的使用
通过捕获传入Task.run()的Callable实例,手动触发其call()方法,再验证Provider的调用:
@ExtendWith(MockitoExtension.class) class MyClassTest { @Mock Task task; @Mock Provider provider; MyClass myClass; @Captor ArgumentCaptor<Callable<Void>> captor; // 泛型匹配:save为void返回时,Callable泛型是Void @BeforeEach public void setup() { myClass = new MyClass(task, provider); } @Test void shouldDoJob() throws Exception { myClass.doYourJob(); // 捕获传入task.run的Callable参数 verify(task).run(captor.capture()); // 获取捕获的Callable并执行其call方法 Callable<Void> capturedCallable = captor.getValue(); capturedCallable.call(); // 验证Provider的save方法被正确参数调用 verify(provider).save("Test"); } }
关键修正点:
- 泛型匹配:如果
Provider.save()是void返回值,对应的Callable泛型应为Void,否则ArgumentCaptor无法正确捕获参数; - 正确触发Callable:通过
captor.getValue()获取捕获的实例,再调用call()方法(原代码直接调用captor.call()是错误的)。
方案二:使用doAnswer让Mock的Task自动执行Callable
配置Mock的Task.run()方法,使其自动执行传入的Callable,无需手动捕获触发:
@ExtendWith(MockitoExtension.class) class MyClassTest { @Mock Task task; @Mock Provider provider; MyClass myClass; @BeforeEach public void setup() { myClass = new MyClass(task, provider); } @Test void shouldDoJob() throws Exception { // 配置Task.run(),执行传入的Callable doAnswer(invocation -> { Callable<?> callable = invocation.getArgument(0); return callable.call(); }).when(task).run(any(Callable.class)); myClass.doYourJob(); // 直接验证Provider的save方法 verify(provider).save("Test"); } }
这种方式更简洁,直接让Mock的Task模拟真实逻辑,执行传入的Callable,后续只需验证Provider的调用即可。
内容的提问来源于stack exchange,提问作者Tirlipirli
相关产品推荐
相关产品推荐

