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

循环使用Mockito argThat出现NullPointerException问题求助

Mockito循环Stub时空指针异常的原因与解决办法

问题背景

循环使用Mockito的argThat进行方法Stub时,当迭代次数≥2会抛出空指针异常:

java.lang.NullPointerException: Cannot invoke "getValue()" because "arg" is null

测试代码片段:

@Test
public void testMy() {
    int numberOfItems = 2;
    List<MyData> myDataList = getTestData(numberOfItems);
    
    for (MyData md : myDataList) {
        // 此处触发NPE
        when(mockedService.someMethod(
               argThat(arg -> Objects.equals(arg.getValue(), md.getMyValue()))))
            .thenReturn(getExpectedResult(md.getMyValue()));
    }
    
    List<MyData> resData = testService.methodUnderTest(myDataList);
    // 断言逻辑
}

被测方法逻辑:

public List<MyData> methodUnderTest(List<MyData> myDataList) {
    myDataList.forEach(myData -> {
            // 业务处理逻辑
            myData.setResult(mockedService.someMethod(new MyRequest(myData.getMyValue())));
        }
    });
    return myDataList;
}

原使用Hamcrest匹配器的写法可正常运行:

when(mockedService.someMethod(
       argThat(hasProperty("value", equalTo(md.getMyValue())))))
    .thenReturn(getExpectedResult(md.getMyValue()));

原因分析

  1. Mockito的Stub执行机制:调用when(mock.method(argThat(...)))时,Mockito会实际执行一次被mock的方法(mock对象默认返回null),这个过程中argThat的lambda匹配器会被触发执行。
  2. 自定义lambda未做空指针防护:直接调用arg.getValue()时,若Mockito内部传入null作为校验参数(比如第二次Stub时,方法调用不符合第一次的匹配规则,触发null参数校验),就会抛出NPE;而Hamcrest的hasProperty匹配器内部已处理空指针场景,不会报错。
  3. 循环Stub的叠加影响:第一次Stub后,mock方法的行为已被记录,第二次Stub时的方法调用会触发Mockito对已有匹配器的校验,此时未防护的lambda就会触发空指针异常。

解决方案

方案1:在lambda中添加空指针校验

修改argThat的lambda表达式,先判断参数非空再调用方法:

when(mockedService.someMethod(
       argThat(arg -> arg != null && Objects.equals(arg.getValue(), md.getMyValue()))))
    .thenReturn(getExpectedResult(md.getMyValue()));

方案2:改用doReturn语法跳过方法调用

doReturn不会触发mock方法的实际执行,从根源避免匹配器被提前执行:

for (MyData md : myDataList) {
    doReturn(getExpectedResult(md.getMyValue()))
        .when(mockedService)
        .someMethod(argThat(arg -> Objects.equals(arg.getValue(), md.getMyValue())));
}

方案3:使用eq匹配器(需重写equals)

如果MyRequest类正确重写了equals和hashCode,可以直接用eq匹配器简化代码:

when(mockedService.someMethod(eq(new MyRequest(md.getMyValue()))))
    .thenReturn(getExpectedResult(md.getMyValue()));

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 14:06:00