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

如何Mock迭代器内部List<Object>的元素添加操作?

问题

请问如何Mock如下代码中迭代器内部的列表元素添加操作?我需要向列表中添加元素,因为我的方法返回List类型,我想对其执行断言,但不知道如何向迭代器内部的列表中添加对象?或者我是否理解有误,应该去Mock Util.jsonToObject方法?

业务代码

public List<Users> getUsers(String userId) {
    List<Users> usersList = new ArrayList<>();
    Table table = dynamoDB.getTable("users");
    ItemCollection<QueryOutcome> items = table.getIndex("userIndex").query(QuerySpec);
    Iterator<Item> iterator = items.iterator();
    while (iterator.hasNext()) {
        // 注:原代码存在笔误,应为 usersList.add
        usersList.add(Util.jsonToObject(iterator.next().toJSONPretty(), Users.class));
    }
    return usersList;
}

测试代码

List<Users> mockList = mock(ArrayList.class);
Users details = new Users("1", UUID.randomUUID().toString(), null, "");
List<Users> usersList = new ArrayList<>();
usersList.add(details);
Table mockTable = mock(Table.class);
Item item = mock(Item.class);
mockTable.putItem(item);
Index mockIndex = mock(Index.class);
ItemCollection<QueryOutcome> mockCollection = mock(ItemCollection.class);
Item mockItem = mock(Item.class);
IteratorSupport<Item, QueryOutcome> mockIterator = mock(IteratorSupport.class);
when(dynamoDB.getTable("users")).thenReturn(mockTable);
when(mockTable.getIndex(anyString())).thenReturn(mockIndex);
when(mockIndex.query(any(QuerySpec.class))).thenReturn(mockCollection);
when(mockCollection.iterator()).thenReturn(mockIterator);
when(mockIterator.hasNext()).thenReturn(true).thenReturn(false);
doReturn(true).when(mockList).add(details);
when(mockIterator.next()).thenReturn(mockItem);
when(mockItem.toJSONPretty()).thenReturn("");
assertSame(dynamoDBService.getUsers("").get(0), usersList);
解决方案

核心问题说明

你mock了mockList并配置它的add方法返回true,但业务代码里是内部新建了一个ArrayList(usersList),这个mockList和业务代码中的列表完全无关,所以你的mock配置根本不会生效,这是导致无法得到预期结果的关键原因。

两种可行解决思路

思路1:Mock Util.jsonToObject 静态方法(更直接)

既然业务代码最终是将Util.jsonToObject的返回值加入列表,直接Mock这个静态方法返回预期的Users对象即可,无需纠结迭代器内部细节:

  1. 确保使用的Mock框架支持静态方法Mock(如PowerMock或Mockito 3.4+配合Mockito-inline)
  2. 修改测试代码:
    // 定义预期的Users对象
    Users expectedUser = new Users("1", UUID.randomUUID().toString(), null, "");
    // Mock静态方法,忽略传入的JSON参数,直接返回预期对象
    mockStatic(Util.class);
    when(Util.jsonToObject(anyString(), eq(Users.class))).thenReturn(expectedUser);
    
    // 保留原有DynamoDB相关Mock逻辑
    when(dynamoDB.getTable("users")).thenReturn(mockTable);
    when(mockTable.getIndex(anyString())).thenReturn(mockIndex);
    when(mockIndex.query(any(QuerySpec.class))).thenReturn(mockCollection);
    when(mockCollection.iterator()).thenReturn(mockIterator);
    // 配置迭代器返回一次元素后结束循环
    when(mockIterator.hasNext()).thenReturn(true).thenReturn(false);
    when(mockIterator.next()).thenReturn(mockItem);
    // JSON内容可随意填写,因为已Mock Util方法
    when(mockItem.toJSONPretty()).thenReturn("{}");
    
    // 执行方法并断言
    List<Users> result = dynamoDBService.getUsers("");
    assertEquals(1, result.size());
    assertEquals(expectedUser, result.get(0));
    

思路2:不Mock Util,让Item返回可正确解析的JSON

如果不想Mock静态方法,可让mock的Item返回能被Util.jsonToObject解析为预期Users的JSON字符串:

  1. 将预期的Users对象转换为符合要求的JSON字符串(可使用Jackson等工具)
  2. 修改测试代码中mockItem.toJSONPretty()的返回值:
    Users expectedUser = new Users("1", UUID.randomUUID().toString(), null, "");
    // 将预期对象转为JSON字符串
    String expectedJson = new ObjectMapper().writeValueAsString(expectedUser);
    
    // 保留原有Mock逻辑,仅修改JSON返回值
    when(mockItem.toJSONPretty()).thenReturn(expectedJson);
    
    // 执行方法并断言
    List<Users> result = dynamoDBService.getUsers("");
    assertEquals(1, result.size());
    assertEquals(expectedUser, result.get(0));
    

总结

  • 无需Mock迭代器内部的列表添加操作,因为业务代码中的列表是方法内新建的,外部无法直接Mock其add方法
  • 更合理的做法是MockUtil.jsonToObject静态方法,或让Mock的Item返回正确的JSON字符串,确保业务代码生成预期列表

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 16:03:18