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

如何让Mockito在for循环迭代时从列表返回指定值?

用Mockito实现方法每次调用返回列表对应值的方案

这个需求在单元测试里挺常见的,Mockito刚好有几种简洁的实现方式,我给你分享两种实用的方案,你可以根据自己的场景选择:

方案一:直接使用thenReturn传入序列值

如果你的循环次数固定(比如这里的10次),而且提前知道每次要返回的数值列表,直接用thenReturn的可变参数特性就可以搞定。Mockito会按你传入的顺序,每次调用方法时依次返回对应的值。

示例代码:

// 准备好你要依次返回的数值列表
List<Long> expectedValues = Arrays.asList(5L, 3L, 7L, 2L, 9L, 1L, 4L, 6L, 8L, 0L);

// mock目标对象
Bar barObj = Mockito.mock(Bar.class);

// 把列表转成数组传给thenReturn,Mockito会按顺序返回每个元素
Mockito.when(barObj.getNumFound()).thenReturn(expectedValues.toArray(new Long[0]));

注意点:

  • 如果调用次数超过了列表的长度,后续的调用会一直返回列表的最后一个元素(Mockito 2.x及以上版本的行为)。所以如果你的循环次数和列表长度一致,这个方案最省心。

方案二:用Answer接口动态处理调用次数

如果你的调用次数不确定,或者需要更灵活的逻辑(比如根据调用次数做额外判断),可以用Answer接口来动态生成返回值。我们可以用一个计数器来记录方法被调用的次数,每次调用时从列表中取出对应索引的元素。

示例代码:

List<Long> expectedValues = Arrays.asList(5L, 3L, 7L, 2L, 9L, 1L, 4L, 6L, 8L, 0L);
Bar barObj = Mockito.mock(Bar.class);

// 用原子计数器来记录调用次数(单线程测试用普通int也可以,原子类更安全)
AtomicInteger callCounter = new AtomicInteger(0);

Mockito.when(barObj.getNumFound()).thenAnswer(invocation -> {
    int currentIndex = callCounter.getAndIncrement();
    // 如果调用次数在列表范围内,返回对应值;否则返回默认值(这里用0L)
    return currentIndex < expectedValues.size() ? expectedValues.get(currentIndex) : 0L;
});

优势:

  • 可以灵活处理调用次数超过列表长度的情况,自定义默认返回值或者抛出异常。
  • 适合动态生成返回值的场景,比如需要根据调用上下文调整返回结果。

完整测试示例

下面是一个包含循环逻辑的完整单元测试例子,你可以直接参考:

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

public class BarTest {

    interface Bar {
        long getNumFound();
    }

    @Test
    void testTotalCalculation() {
        // 1. 准备预期的返回值和预期总和
        List<Long> expectedValues = Arrays.asList(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L);
        long expectedTotal = expectedValues.stream().mapToLong(Long::longValue).sum();

        // 2. mock Bar对象并设置返回逻辑(二选一即可)
        Bar barObj = Mockito.mock(Bar.class);

        // 方案一:用thenReturn
        Mockito.when(barObj.getNumFound()).thenReturn(expectedValues.toArray(new Long[0]));

        // 方案二:用Answer
        // AtomicInteger callCounter = new AtomicInteger(0);
        // Mockito.when(barObj.getNumFound()).thenAnswer(invocation -> {
        //     int idx = callCounter.getAndIncrement();
        //     return idx < expectedValues.size() ? expectedValues.get(idx) : 0L;
        // });

        // 3. 执行你的业务逻辑
        long total = 0;
        for (int i = 0; i < 10; i++) {
            long numFound = barObj.getNumFound();
            total += numFound;
        }

        // 4. 验证结果和调用次数
        Assertions.assertEquals(expectedTotal, total);
        Mockito.verify(barObj, Mockito.times(10)).getNumFound();
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:15:00