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

为何Mockito参数匹配器无法识别建造者模式创建的对象?

Groovy测试中Mockito ArgumentCaptor无法识别自定义对象的原因与解决办法

自定义Java类代码

package com.example.objects;

import java.util.Objects;

public class MyExampleClass extends SomeBaseClass {

    private String param1;
    private String param2;

    private MyExampleClass(String param1, String param2) {
        this.param1 = param1;
        this.param2 = param2;
    }

    MyExampleClass() {
    }

    public String getParam1() {
        return param1;
    }

    public String getParam2() {
        return param2;
    }

    public static class Builder {
        private String param1;
        private String param2;

        public Builder setParam1(String param1) {
            this.param1 = param1;
            return this;
        }

        public Builder setParam2(String param2) {
            this.param2 = param2;
            return this;
        }
        
        public MyExampleClass build() {
            Objects.requireNonNull(param1,"blahblah");
            Objects.requireNonNull(param2,"blahblah");
            return new MyExampleClass(param1, param2);
        }
    }
}

Groovy测试代码

def captor = ArgumentCaptor.forClass(MyExampleClass)
Mockito.verify(mockObject).someMethod(captor.capture())

报错信息

Wanted but not invoked:
mockObject.someMethod(
 <Capturing argument>
);
-> at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)

However, there was exactly 1 interaction with this mock:
mockObject.someMethod(
    com.example.objects.MyExampleClass@47a7a101
);

原因分析

问题核心是Groovy与Java的方法调用机制差异:

  • Java中,Mockito.verify(mock).method(captor.capture())会将captor.capture()识别为参数匹配器(Matcher),用于捕获方法实际接收的参数。
  • Groovy中会优先执行captor.capture(),将其返回的默认值(对象类型为null)作为参数传递给someMethod,而非把capture()本身作为Matcher注册给Mockito。这导致Mockito期望的是someMethod(null),但实际调用的是someMethod(MyExampleClass实例),最终匹配失败报错。

解决办法

方法1:用括号强制参数传递逻辑

通过额外括号让Groovy将captor.capture()作为参数传递,而非提前执行:

def captor = ArgumentCaptor.forClass(MyExampleClass)
Mockito.verify(mockObject).someMethod((captor.capture()))

方法2:使用@Captor注解创建捕获器

借助Mockito的@Captor注解可以规避Groovy动态解析的问题,代码更简洁:

import org.mockito.Captor
import org.mockito.MockitoAnnotations

@Captor
ArgumentCaptor<MyExampleClass> captor

@Before
void setup() {
    MockitoAnnotations.openMocks(this) // 初始化注解
}

void testMethod() {
    // 执行测试逻辑...
    
    Mockito.verify(mockObject).someMethod(captor.capture())
    // 断言捕获到的对象
    def capturedObj = captor.value
    assert capturedObj.param1 == "预期值"
}

方法3:显式使用匹配器包裹

通过Mockito.argThat包裹捕获逻辑,确保Groovy正确识别Matcher:

def captor = ArgumentCaptor.forClass(MyExampleClass)
Mockito.verify(mockObject).someMethod(Mockito.argThat { 
    captor.capture()
    return true
})

内容的提问来源于stack exchange,提问作者Lord Arryn

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 14:44:56