argumentcaptor 无法直接捕获带具体泛型参数的类型(如 list),需用原始类型(如 argumentcaptor)声明并手动转型;泛型方法需按实际传入类型分别捕获,@captor 字段也须用原始类型;复杂场景可用 doanswer 替代。

Mockito 的 ArgumentCaptor 可以捕获泛型方法的入参,但需注意类型擦除带来的限制——不能直接用 ArgumentCaptor<list>></list> 这类带具体泛型参数的写法,因为 Java 运行时无法识别泛型类型信息。
用原始类型声明 captor,再通过泛型方法获取值
推荐做法是用原始类型(如 ArgumentCaptor<list></list>)声明,然后在 getValue() 或 getAllValues() 后手动转型。Mockito 不校验泛型,只关心实际运行时对象类型。
- ✅ 正确写法:
ArgumentCaptor<list> listCaptor = ArgumentCaptor.forClass(List.class);</list> - ❌ 错误写法:
ArgumentCaptor<list>> listCaptor = ArgumentCaptor.forClass(List.class);</list>(编译不通过) - 调用
verify(mock).method(listCaptor.capture());后,可用List<string> captured = (List<string>) listCaptor.getValue();</string></string>安全转型(前提是传入的确实是List<string></string>)
对泛型接口/方法使用通配符或类型变量捕获
若被测方法签名含泛型参数(如 <t> void process(T item)</t>),ArgumentCaptor 本身不支持泛型类型变量,只能按实际传入的实参类型捕获。
- 例如:调用
mock.process("hello")→ 用ArgumentCaptor<string></string> - 调用
mock.process(Arrays.asList(1, 2))→ 用ArgumentCaptor<list></list>,再转型为List<integer></integer> - 无法用一个 captor 同时捕获多种泛型实参;需按测试场景分别定义
配合 @Captor 注解和泛型字段(需类型提示)
使用 @Captor 时,字段声明仍需用原始类型,否则编译失败。可通过注释或命名体现预期泛型语义。
- // 表示预期捕获 List
@Captor ArgumentCaptor<list> userListCaptor;</list>- 验证后:
List<user> users = (List<user>) userListCaptor.getValue();</user></user> - 建议加
assertThat(users).isNotEmpty();等断言,避免空指针或转型异常
替代方案:用 doAnswer + 自定义捕获逻辑(适合复杂泛型场景)
当需要精确匹配泛型结构(如嵌套泛型、通配符边界)或多次调用需区分时,doAnswer 更灵活:
AtomicReference<list>> capturedRef = new AtomicReference();</list>doAnswer(invocation -> { capturedRef.set((List<string>) invocation.getArgument(0)); return null; })</string>- 优点:绕过类型擦除限制,直接持有强类型引用;缺点:代码略冗长
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











