Mockito Argument Captor使用问题:仅验证指定参数的方法调用
解决Mockito中仅验证特定参数方法调用次数的问题
你的问题核心是混淆了方法总调用次数和特定参数的方法调用次数,原代码里的verify(action, times(1)).perform(captor.capture())是在验证perform方法总共被调用1次,但实际你调用了2次(Pear和Apple各一次),所以才会触发TooManyActualInvocations错误。下面针对你的需求(仅验证perform(Pear.class)被调用1次,忽略Apple的调用次数)给出适配Mockito 1.10的解决方案:
方案1:仅验证调用次数(无需捕获参数)
这是最直接的方案,使用Mockito内置的isA()参数匹配器,精准匹配Pear类型的参数,让verify只统计符合该类型的调用次数:
@Test public void simpleTest() { Action action = mock(Action.class); action.perform(new Pear()); action.perform(new Apple()); // 仅验证传入Pear实例的perform调用次数为1次 verify(action, times(1)).perform(isA(Pear.class)); }
这个方案完全贴合你的业务场景(类似确保save(MyDomainObject)被调用一次),不需要关心其他参数的调用次数,也不会受未知调用次数的影响。
方案2:需要捕获Pear参数做进一步断言
如果你需要获取传入的Pear实例,验证其属性或状态,可以结合ArgumentCaptor和过滤逻辑实现:
@Test public void simpleTest() { ArgumentCaptor<IFruit> captor = ArgumentCaptor.forClass(IFruit.class); Action action = mock(Action.class); action.perform(new Pear()); action.perform(new Apple()); // 捕获所有perform方法的调用参数(兼容任意次数的调用) verify(action, atLeast(0)).perform(captor.capture()); // 筛选出Pear类型的参数并统计调用次数 long pearInvocationCount = captor.getAllValues().stream() .filter(fruit -> fruit instanceof Pear) .count(); // 断言Pear参数的调用次数为1次 assertEquals(1, pearInvocationCount); // 可选:获取捕获的Pear实例做属性验证 Pear capturedPear = (Pear) captor.getAllValues().stream() .filter(fruit -> fruit instanceof Pear) .findFirst() .orElse(null); // 比如验证Pear的属性:assertEquals("green", capturedPear.getColor()); }
这里用atLeast(0)是为了兼容Apple参数的调用次数(0次或多次),避免因为总调用次数不符合预期而报错,只聚焦你关心的Pear参数调用。
扩展:自定义参数匹配器(精准匹配属性)
如果需要更精细的匹配(比如不仅是类型,还要验证参数的特定属性),可以自定义ArgumentMatcher:
static class PearMatcher extends ArgumentMatcher<IFruit> { @Override public boolean matches(Object argument) { if (!(argument instanceof Pear)) { return false; } // 可以扩展属性验证,比如: // Pear pear = (Pear) argument; // return "green".equals(pear.getColor()); return true; } }
然后在verify中使用自定义匹配器:
verify(action, times(1)).perform(argThat(new PearMatcher()));
内容的提问来源于stack exchange,提问作者Bogdan Samondros
相关产品推荐
相关产品推荐

