2017-03-09 4 views
0

私は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); 

ここでは、比較の失敗の詳細です:

を:ここで Comparison Failure Window Screenshot.

は、私がテストしてる方法であり、

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); } 

私はマッキントッシュからのマッチを試しました、運はありません。私は、正規表現を働かせるように見えることはできません。 Matchと同様に、以下のRegex:(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3})。私は無視する必要がある部分を選択します。あなたのコードの後に​​テストを書いているように

+0

それは私が私がテストしていたクラス/メソッドへの変更をしないことがベストです。 – Amiko

答えて

1

nowメソッドのオーバーライドを使用して、必要なオブジェクト(LocalDateTimeを含む)にアクセスできるように、ベストプラクティスにはClockが必要です。

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's answerのように、あなたは新しい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 supports nativelyパラメータ化クエリ、この方法を切り替えることを考慮すべきです。あなたもsupport named parameters using related classesすることができます。

+0

詳しく説明してくれてありがとうございます。私はあなたの答えから多くを学んだ。そして、それは動作します。私はこの質問がある、私はテストしているクラスに余分なものを触れたり追加したりすることなく、Mockitoのマッチメソッドでそれを行う方法があるのだろうか?マッチ()のある方法があるかどうか不思議です。 Likeを除いて、DateTimeを除くすべて。 – Amiko

+0

@Amiko期待通りのクエリを膨大な読み込み不可能な正規表現自体に変換することなく、 'matches 'を使ってそれを行う良い方法は考えられません(例えば、エスケープツールを使用してクエリ式を構築し、あなたが書いた表現)。それでも読み込みや管理は難しく、正しい日付がクエリの一部であるかどうかテストしません。もう1つの解決策は、ArgumentCaptorを使用してクエリをキャプチャし、類似した可読性/保守性/カバレッジコストで日付を解析または解析することです。いずれの場合でもどちらのソリューションもお勧めできません。 –

1

は思える: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()) + 
    [...] 
} 

と、既存のコードとの整合性を保つために:私はどうなるのか

をすることができますユニットきちんとテストをするように、関数にlocaledatetimeを渡すことです

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); 
} 

今度は、ユニットテストが正しく部は、第二の方法をテストし、(それを試験方法に内蔵localedatetimeを渡すことによって)第一の方法は簡単であることができます。

関連する問題