如何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对象即可,无需纠结迭代器内部细节:
- 确保使用的Mock框架支持静态方法Mock(如PowerMock或Mockito 3.4+配合Mockito-inline)
- 修改测试代码:
// 定义预期的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字符串:
- 将预期的
Users对象转换为符合要求的JSON字符串(可使用Jackson等工具) - 修改测试代码中
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方法 - 更合理的做法是Mock
Util.jsonToObject静态方法,或让Mock的Item返回正确的JSON字符串,确保业务代码生成预期列表
内容的提问来源于stack exchange,提问作者user21476047
相关产品推荐
相关产品推荐

