有没有办法修复一个应该 return 由 ResultSet 组成的字符串的测试?

Is there a way to fix a Test which should return a string made of ResultSet?

我有一个从结果集中创建字符串的函数。以及发送消息的那个。你可以在下面看到它们

public String createStringReport(ResultSet resultSet) throws SQLException{
    StringBuilder reportData = new StringBuilder("");
    int columns = 0;
    if(resultSet.getMetaData() != null) {
        columns = resultSet.getMetaData().getColumnCount();
        while (resultSet.next()) {
            for (int i = 1; i <= columns; i++) {
                reportData.append(resultSet.getString(i)).append("\t");
            }
            reportData.append("\n");
        }
    }
    return !reportData.toString().isEmpty() ? reportData.toString() : "No data";
}

private void sendStringReport(String reportData) {
    for (User u: users) {
        sender.send(u, reportData);
        log.info("send report - " + report.getName() + " to" + u.getName());
    }
}

我需要编写一个测试,使用之前生成的参数字符串调用发送方。这就是我现在拥有的:

@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(resultSet.getMetaData()).thenReturn(rsmd);
    doReturn(rsmd).when(resultSet).getMetaData();

    StringBuilder reportData = new StringBuilder("");
    if(resultSet.getMetaData() != null) {
        while (resultSet.next()) {
            for (int i = 1; i <= columns; i++) {
                reportData.append(result).append("\t");
            }
            reportData.append("\n");
        }
    }

    reportCreator.run();
    verify(sender, Mockito.times(users.size())).send(any(User.class), eq(reportData.toString));
}

不幸的是,有人告诉我:

Argument(s) are different! Wanted:
telegramSender.send(
    <any reportbot.entity.User>,
    "somestring somestring  
somestring  somestring  
"
);
-> at ru.phoenixdnr.reportbot.ReportCreatorTest$Run.shouldGenerateStringReportWhenThreadRunHasData(ReportCreatorTest.java:233)
Actual invocations have different arguments:
telegramSender.send(
    User(id=1, idTelegram=2, name=892e0f69-c10e-4961-b22e-11de333fbb55, email=73507828-9c7a-4026-8599-5e6c8c62e3c7),
    "No data"
);

为什么报告数据是空的? 我怎样才能解决这个问题?我已经尝试了一个星期了,但没有任何帮助。

您错过了对 ResultSetMetadatagetColumnCount 电话的嘲笑:

when(rsmd.getColumnCount()).thenReturn(2);

问题似乎是您:

  • 设置模拟结果集,
  • 在构建预期输出时从中读取结果,
  • 调用您尝试测试的方法,具有相同的结果集

被测方法运行时,发现结果集已经耗尽(或者至少.next()returnsfalse),所以没有更多的数据从中读取。因此你得不到任何数据。

如果生成预期文本的代码使用单独的结果集,则不会出现此问题。

解决此问题的一种方法是将所有 ResultSet 模拟设置代码移动到一个单独的方法中,该方法创建并 return 模拟 ResultSet。这样您就可以调用此方法两次以获得两个不同的模拟 ResultSet,一个用于创建结果集以用于创建预期结果,一次用于传递给报告创建者。

另一个修复方法是在不使用模拟 ResultSet 的情况下生成预期的输出。你知道 ResultSet.getMetaData() 不会 return null,所以空检查是不必要的,你也知道模拟 ResultSet 中有多少行,所以你可以用 for 循环替换 while 循环。