如何修复基于ResultSet生成字符串报告的单元测试返回No data的问题
问题原因分析
- ResultSet迭代器被提前耗尽:你在测试代码中提前调用了
resultSet.next()构造预期的报告字符串,你给next()方法预设的返回规则是第一次true、第二次false,提前遍历后,后续reportCreator.run()执行createStringReport方法时,再调用next()会直接返回false,数据遍历逻辑完全没执行,生成的报告内容为空,最终返回No data。 - 未给ResultSetMetaData的getColumnCount方法打桩:
createStringReport方法中会调用resultSet.getMetaData().getColumnCount()获取列数,你只mock了ResultSetMetaData对象,没有给getColumnCount()设置返回值,Mockito默认会返回基本类型的默认值0,后续列遍历的for循环(i从1到0)不会执行,就算有数据也无法拼接内容。 - 测试代码语法小错误:最后的验证语句中
eq(reportData.toString)漏了括号,应该是toString(),否则会把方法引用当成参数,也会导致匹配失败。
修复方案
按以下步骤修改测试代码即可:
- 不要通过遍历mock的
resultSet构造预期字符串,直接硬编码或者用不触碰resultSet的方式生成预期值,避免提前耗尽迭代器。 - 给
ResultSetMetaData补充getColumnCount的打桩逻辑,示例如下:
final ResultSetMetaData rsmd = mock(ResultSetMetaData.class); when(rsmd.getColumnCount()).thenReturn(2); // 补充这一行 when(resultSet.getMetaData()).thenReturn(rsmd);
- 修复验证语句的语法错误:
verify(sender, Mockito.times(users.size())).send(any(User.class), eq(reportData.toString()));
修改后的完整测试示例:
@Test public void shouldGenerateStringReportWhenThreadRunHasData() throws SQLException { String result = "somestring"; Report report = getReport(ReportType.STRING); ReportCreator reportCreator = new StringReportCreator(report, users, sender, dataSource, unexpectedErrorCounter); when(resultSet.getString(anyInt())).thenReturn(result); when(resultSet.next()).thenReturn(true).thenReturn(false); int columns = 2; final ResultSetMetaData rsmd = mock(ResultSetMetaData.class); // 补充列数打桩 when(rsmd.getColumnCount()).thenReturn(columns); when(resultSet.getMetaData()).thenReturn(rsmd); // 直接构造预期字符串,不调用resultSet的next方法 String expectedReport = result + "\t" + result + "\t\n"; reportCreator.run(); verify(sender, Mockito.times(users.size())).send(any(User.class), eq(expectedReport)); }
内容的提问来源于stack exchange,提问作者Margarita
相关产品推荐
相关产品推荐

