在忽略localdateTime.now()产生的时间差的同时,我该如何断言查询



我遇到了localdateTime.now()方法所产生的时间的问题,我想在忽略它产生的时间的同时断言整个查询。这是代码:

 @Test
public void getLastDrawResult_lotteryIdPresent() {
    Optional<Long> lotteryId = Optional.of(3L);
    Optional<String> name = Optional.empty();
    Optional<String> byName = Optional.empty();
    Optional<String> byDate = Optional.empty();
    Optional<Boolean> jackpotOnly = Optional.empty();
    String query = QUERY_MAIN_BLOCK.replace("/*statement0*/", LocalDateTime.now().plusMinutes(buyingLock).toString()) + CONDITION_SEARCH_BY_LAST_DRAW_RESULT;
    String updatedQuery = query.replace("/*statement1*/", " WHERE d.lottery_info_id = 3") + " AND d.lottery_info_id = 3";
    DrawResultDto drawResultDto = DrawResultDto.builder().id(3L).build();
    List<DrawResultDto> expectedDrawResultDto = singletonList(drawResultDto);
    when(jdbcTemplate.query(updatedQuery, drawResultDtoQueryBuilder.queryMapper)).thenReturn(expectedDrawResultDto);
    List<DrawResultDto> actualDrawResultDto = drawResultDtoQueryBuilder.getLastDrawResult(lotteryId, name, byName, byDate, jackpotOnly);
    verify(jdbcTemplate).query(updatedQuery, drawResultDtoQueryBuilder.queryMapper);
    assertEquals(expectedDrawResultDto, actualDrawResultDto);

这是比较失败的详细信息,因此您可以更了解我需要忽略的内容:比较失败窗口屏幕截图。

这是我正在测试的方法:

public List<DrawResultDto> getLastDrawResult(Optional<Long> lotteryId, Optional<String> name, Optional<String> byName, Optional<String> byDate, Optional<Boolean> jackpotOnly) {
    String query = QUERY_MAIN_BLOCK.replace("/*statement0*/", LocalDateTime.now().plusMinutes(buyingLock).toString()) +
            CONDITION_SEARCH_BY_LAST_DRAW_RESULT;
    StringBuilder builder = new StringBuilder();
    if (lotteryId.isPresent()) {
        builder.append(query.replace("/*statement1*/", " WHERE d.lottery_info_id = " + lotteryId.get()))
                .append(String.format(" AND d.lottery_info_id = %d", lotteryId.get()));
    } else {
        builder.append(query);
        name.ifPresent(nameValue -> builder.append(" AND lower(li.name) LIKE '%").append(SqlUtils.escapeLike(nameValue).toLowerCase()).append("%' "));
        jackpotOnly.ifPresent(jackpotOnlyValue -> {
            if (jackpotOnlyValue) {
                builder.append(" AND ").append(CONDITION_SEARCH_BY_JACKPOT_WIN);
            }
        });
        byName.ifPresent(s -> builder.append(" ORDER BY li.name ").append(SqlUtils.escapeLike(s)));
        byDate.ifPresent(s -> builder.append(" ORDER BY nfd.nearestDrawDate ").append(SqlUtils.escapeLike(s)));
        if (!byName.isPresent() && !byDate.isPresent()){
            builder.append(" ORDER BY li.name desc ");
        }
    }
    return jdbcTemplate.query(builder.toString(), queryMapper);
}

我尝试从Mockito做Matches(),没有运气。我似乎无法让正则正则可以正常工作。像匹配以下所有义务以外的一切:(d{4}-d{2}-d{2}Td{2}:d{2}:d{2}.d{3})。选择我需要忽略的零件。

最佳实践将涉及您注入时钟,这将使您通过now方法的覆盖需要访问任何对象(包括localdateTime)。

public List<DrawResultDto> getLastDrawResult(
    Optional<Long> lotteryId,
    Optional<String> name,
    Optional<String> byName,
    Optional<String> byDate,
    Optional<Boolean> jackpotOnly,
    Clock clock) {
  LocalDateTime localDateTime = LocalDateTime.now(clock);
  /* ... */
}

如Ash的答案中,您可以与当前签名的方法过载,以创建新的SystemClock,然后测试接受时钟的方法。

/** Your original method signature. No changes to any calling code. */
public List<DrawResultDto> getLastDrawResult(
    Optional<Long> lotteryId,
    Optional<String> name,
    Optional<String> byName,
    Optional<String> byDate,
    Optional<Boolean> jackpotOnly) {
  return getLastDrawResult(lotteryId, name, byName, byDate, jackpotOnly,
      Clock.systemDefaultZone());
}
/** Your original method implementation. Test this one. */
public List<DrawResultDto> getLastDrawResult(
    Optional<Long> lotteryId,
    Optional<String> name,
    Optional<String> byName,
    Optional<String> byDate,
    Optional<Boolean> jackpotOnly,
    Clock clock) {
  LocalDateTime localDateTime = LocalDateTime.now(clock);
  /* ... */
}

以这种方式,在您的测试中,您可以从Clock.fixed中传递一个值。

单独考虑,您应该强烈考虑将此方法切换到参数化的查询,JDBCTEMPLATE本地支持。您甚至可以使用相关类支持命名参数。

似乎您是在代码之后写测试:P(否则您永远不会遇到这样的问题)。

我要做的是将本土时间传递到该函数,以便您可以正确测试它:

public List<DrawResultDto> getLastDrawResult(LocalDateTime t, Optional<Long> lotteryId, Optional<String> name, Optional<String> byName, Optional<String> byDate, Optional<Boolean> jackpotOnly) {
    String query = QUERY_MAIN_BLOCK.replace("/*statement0*/", t.plusMinutes(buyingLock).toString()) +
    [...]
}

并保持与现有代码保持一致,请保留实际签名:

public List<DrawResultDto> getLastDrawResult(Optional<Long> lotteryId, Optional<String> name, Optional<String> byName, Optional<String> byDate, Optional<Boolean> jackpotOnly) {
    return getLastDrawResult(LocaleDateTime.now(), Optional<Long> lotteryId, Optional<String> name, Optional<String> byName, Optional<String> byDate, Optional<Boolean> jackpotOnly);
}

现在,您可以正确测试第一个方法(通过将其传递给测试方法内的本地体内),单位测试第二种方法是微不足道的。

最新更新