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

Mockito报错:匹配器数量超出预期,如何复用已捕获值?

解决Mockito匹配器数量不匹配及值复用问题

首先,你遇到的核心问题是Mockito匹配器的使用范围错误:你在方法参数的内部(Document构造器中)嵌套使用了anyString()、anyInt()等匹配器,Mockito会将这些都视为独立的方法参数匹配器,但updateOne只有3个方法参数,导致匹配器数量(4个)和参数数量(3个)不匹配。同时要实现两个_id值一致,需要在匹配或存根阶段关联两个参数中的值。

方案1:使用ArgumentCaptor+argThat在匹配阶段验证值一致性并复用

这种方式会在Mockito匹配调用时就验证两个_id的值一致,同时捕获值用于后续存根逻辑:

// 定义捕获器,用于捕获第一个参数中的_id字符串
ArgumentCaptor<String> accountIdCaptor = ArgumentCaptor.forClass(String.class);

when(mongoCollection.updateOne(
    // 匹配第一个参数:验证是包含非空_id的Document,同时捕获该_id
    argThat(filterDoc -> {
        String id = filterDoc.getString("_id");
        if (id != null) {
            accountIdCaptor.capture();
            return true;
        }
        return false;
    }),
    // 匹配第二个参数:验证$set中的_id和捕获到的第一个_id一致,且funds是整数
    argThat(updateDoc -> {
        Document setDoc = updateDoc.get("$set", Document.class);
        return setDoc != null 
            && accountIdCaptor.getValue().equals(setDoc.getString("_id"))
            && setDoc.getInteger("funds") != null;
    }),
    // 匹配第三个参数:任意UpdateOptions实例
    any(UpdateOptions.class)
)).thenAnswer(invocation -> {
    // 复用捕获到的_id,将第三个参数存入map
    fundsByAccount.put(accountIdCaptor.getValue(), invocation.getArgument(2));
    return UpdateResult.acknowledged(1); // 返回合法的UpdateResult
});

方案2:在thenAnswer中直接处理参数验证与值复用

如果不需要在匹配阶段就验证_id一致性,而是在存根逻辑中处理,可以简化代码,同时避免匹配器数量问题:

when(mongoCollection.updateOne(any(Document.class), any(Document.class), any(UpdateOptions.class)))
    .thenAnswer(invocation -> {
        // 从第一个参数中获取_id
        Document filterDoc = invocation.getArgument(0);
        String accountId = filterDoc.getString("_id");
        
        // 可选:验证第二个参数中的_id与第一个一致
        Document updateDoc = invocation.getArgument(1);
        Document setDoc = updateDoc.get("$set", Document.class);
        assert setDoc != null && accountId.equals(setDoc.getString("_id"));
        
        // 将_id和第三个参数存入map
        UpdateOptions options = invocation.getArgument(2);
        fundsByAccount.put(accountId, options);
        
        return UpdateResult.acknowledged(1);
    });

关键说明

  • 避免在方法参数的内部结构(如Document构造、方法调用)中直接使用Mockito匹配器,Mockito的匹配器仅作用于方法的顶层参数。
  • 两种方案的区别:方案1在Mockito匹配调用时就会过滤掉_id不一致的调用,方案2允许调用进入存根逻辑,再进行验证(适合需要记录调用同时验证参数的场景)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 04:31:19