Mockito测试中如何验证方法调用时传入的Consumer类型参数?
解决方案
所有方案均基于Mockito原生能力实现,无需引入PowerMock,按优先级推荐如下:
方案1:ArgumentCaptor 捕获Consumer并验证行为(最优推荐)
单元测试核心是验证逻辑行为正确性,而非对象身份一致性,该方案通过捕获传入的Consumer,执行后验证其逻辑是否符合预期,稳定性最高,适配后续代码调整。
测试代码示例:
import org.mockito.ArgumentCaptor; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; @RunWith(MockitoJUnitRunner.class) public class MyServiceTest { @Mock SomeLib someLib; @InjectMocks MyService myService; // 如果需要验证日志,可以引入日志捕获工具,比如LogCaptor,此处省略对应依赖配置 @Test public void shouldCallEnhanceMethodWithRightParams() { // 1. 定义Consumer类型的参数捕获器 ArgumentCaptor<Consumer<SomeType>> consumerCaptor = ArgumentCaptor.forClass(Consumer.class); // 2. 执行被测业务方法 myService.doSomething(); // 3. 验证方法调用,同时捕获第二个Consumer参数 verify(someLib).enhanceMethod(eq("hello"), consumerCaptor.capture()); // 4. 构造测试用的入参实例,执行捕获到的Consumer SomeType testData = new SomeType(); // 可根据测试需要给testData设置自定义属性值 Consumer<SomeType> capturedConsumer = consumerCaptor.getValue(); capturedConsumer.accept(testData); // 5. 验证Consumer执行后的行为符合预期 // 示例1:如果processData有业务副作用,比如修改数据、调用其他依赖,直接验证对应行为 // 示例2:如果是打印日志,用日志捕获工具验证日志输出 // assertThat(logCaptor.getInfoLogs()).contains(testData.toString()); } }
方案2:argThat 自定义匹配器(适合快速校验场景)
如果仅需要简单校验传入的Consumer是否为目标方法引用,可以用Mockito的自定义参数匹配器实现,该方案代码更简洁,但稳定性低于方案1。
测试代码示例:
import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; @Test public void shouldCallEnhanceMethodWithRightParams() { myService.doSomething(); // 自定义匹配规则,校验Consumer的来源是否为processData方法 verify(someLib).enhanceMethod(eq("hello"), argThat(consumer -> consumer != null && consumer.toString().contains("processData") )); }
注意:该方案依赖JVM对方法引用
toString()的输出格式,不同JDK版本实现可能存在差异,若后续将方法引用替换为Lambda表达式,匹配规则会失效,仅适合临时校验使用。
方案3:调整业务代码可测试性(可选)
如果不需要严格校验Consumer的执行逻辑,仅校验入参身份,可以将processData方法的private修饰符去掉,改为包级私有,测试类和业务类保持同一包结构即可直接匹配方法引用:
// 业务代码调整:去掉private修饰符 void processData(SomeType data) { log.info(data); }
测试代码直接用eq匹配:
@Test public void shouldCallEnhanceMethodWithRightParams() { myService.doSomething(); verify(someLib).enhanceMethod(eq("hello"), eq(myService::processData)); }
注意:该方案依赖JVM对方法引用生成的实例是否相等,部分JDK版本中同一方法多次生成的Consumer实例可能不相等,存在测试误报的风险。
内容的提问来源于stack exchange,提问作者αƞjiβ
相关产品推荐
相关产品推荐

