1. 概要

Hamcrestは、単体テストのアサーションをよりシンプルで読みやすくするための静的マッチャーを提供します。利用可能なマッチャーのいくつかの探索を開始できますここ

この記事では、数値に関連するマッチャーについて詳しく説明します。

2. 設定

Hamcrestを取得するには、次のMaven依存関係をpom.xmlに追加する必要があります。

<dependency>
    <groupId>org.hamcrest</groupId>
    <artifactId>java-hamcrest</artifactId>
    <version>2.0.0.0</version>
</dependency>

最新のHamcrestバージョンは、 MavenCentralにあります。

3. 近接マッチャー

ここで取り上げる最初のマッチャーのセットは、いくつかの要素が値+/-エラーに近いかどうかをチェックするものです。

より正式には:

value - error <= element <= value + error

上記の比較が真の場合、アサーションは合格です。

実際に見てみましょう!

3.1. isClose With Double

と呼ばれるdouble変数に格納された数値があるとしましょう実際。 そして、私たちはテストしたい実際 1+/-0.5に近いです。

あれは:

1 - 0.5 <= actual <= 1 + 0.5
    0.5 <= actual <= 1.5

次に、 isClosematcherを使用して単体テストを作成しましょう。

@Test
public void givenADouble_whenCloseTo_thenCorrect() {
    double actual = 1.3;
    double operand = 1;
    double error = 0.5;
 
    assertThat(actual, closeTo(operand, error));
}

1.3は0.5から1.5の間なので、テストは合格です。 同様に、ネガティブシナリオをテストできます。

@Test
public void givenADouble_whenNotCloseTo_thenCorrect() {
    double actual = 1.6;
    double operand = 1;
    double error = 0.5;
 
    assertThat(actual, not(closeTo(operand, error)));
}

次に、異なるタイプの変数を使用した同様の状況を見てみましょう。

3.2. isClose With BigDecimal

isCloseはオーバーロードされており、double値と同じように使用できますが、BigDecimalオブジェクトを使用します

@Test
public void givenABigDecimal_whenCloseTo_thenCorrect() {
    BigDecimal actual = new BigDecimal("1.0003");
    BigDecimal operand = new BigDecimal("1");
    BigDecimal error = new BigDecimal("0.0005");
    
    assertThat(actual, is(closeTo(operand, error)));
}

@Test
public void givenABigDecimal_whenNotCloseTo_thenCorrect() {
    BigDecimal actual = new BigDecimal("1.0006");
    BigDecimal operand = new BigDecimal("1");
    BigDecimal error = new BigDecimal("0.0005");
    
    assertThat(actual, is(not(closeTo(operand, error))));
}

isマッチャーは、追加のロジックを追加せずに、他のマッチャーのみを装飾することに注意してください。 アサーション全体を読みやすくするだけです。

近接マッチャーについては以上です。 次に、オーダーマッチャーについて見ていきます。

4. オーダーマッチャー

その名前が示すように、これらのマッチャーは注文に関するアサーションを作成するのに役立ちます。

それらの5つがあります:

  • compareEqualTo
  • より大きい
  • 以上
  • 未満
  • lessThanOrEqualTo

それらはほとんど自明ですが、いくつかの例を見てみましょう。

4.1. 整数Valuesのオーダーマッチャー

最も一般的なシナリオは、これらのマッチャーを数字で使用するです。

それでは、先に進んでいくつかのテストを作成しましょう。

@Test
public void given5_whenComparesEqualTo5_thenCorrect() {
    Integer five = 5;
    
    assertThat(five, comparesEqualTo(five));
}

@Test
public void given5_whenNotComparesEqualTo7_thenCorrect() {
    Integer seven = 7;
    Integer five = 5;

    assertThat(five, not(comparesEqualTo(seven)));
}

@Test
public void given7_whenGreaterThan5_thenCorrect() {
    Integer seven = 7;
    Integer five = 5;
 
    assertThat(seven, is(greaterThan(five)));
}

@Test
public void given7_whenGreaterThanOrEqualTo5_thenCorrect() {
    Integer seven = 7;
    Integer five = 5;
 
    assertThat(seven, is(greaterThanOrEqualTo(five)));
}

@Test
public void given5_whenGreaterThanOrEqualTo5_thenCorrect() {
    Integer five = 5;
 
    assertThat(five, is(greaterThanOrEqualTo(five)));
}

@Test
public void given3_whenLessThan5_thenCorrect() {
   Integer three = 3;
   Integer five = 5;
 
   assertThat(three, is(lessThan(five)));
}

@Test
public void given3_whenLessThanOrEqualTo5_thenCorrect() {
   Integer three = 3;
   Integer five = 5;
 
   assertThat(three, is(lessThanOrEqualTo(five)));
}

@Test
public void given5_whenLessThanOrEqualTo5_thenCorrect() {
   Integer five = 5;
 
   assertThat(five, is(lessThanOrEqualTo(five)));
}

理にかなっていますよね? 述語が何を主張しているのかを理解するのがいかに簡単であるかに注意してください。

4.2. 文字列値を持つマッチャーを注文する

数値を比較することは完全に理にかなっていますが、多くの場合、他のタイプの要素を比較すると便利です。 そのため、オーダーマッチャーは、Comparableインターフェイスを実装するすべてのクラスに適用できます。

Strings:の例をいくつか見てみましょう。

@Test
public void givenBenjamin_whenGreaterThanAmanda_thenCorrect() {
    String amanda = "Amanda";
    String benjamin = "Benjamin";
 
    assertThat(benjamin, is(greaterThan(amanda)));
}

@Test
public void givenAmanda_whenLessThanBenajmin_thenCorrect() {
    String amanda = "Amanda";
    String benjamin = "Benjamin";
 
    assertThat(amanda, is(lessThan(benjamin)));
}

String は、CompareableインターフェースからのcompareToメソッドにアルファベット順を実装します。

したがって、「アマンダ」という単語が「ベンジャミン」という単語の前に来ることは理にかなっています。

4.3. LocalDate値を使用してマッチャーを注文する

Strings と同じように、日付を比較できます。 上で作成したのと同じ例を見てみましょうが、LocalDateオブジェクトを使用しています。

@Test
public void givenToday_whenGreaterThanYesterday_thenCorrect() {
    LocalDate today = LocalDate.now();
    LocalDate yesterday = today.minusDays(1);
 
    assertThat(today, is(greaterThan(yesterday)));
}

@Test
public void givenToday_whenLessThanTomorrow_thenCorrect() {
    LocalDate today = LocalDate.now();
    LocalDate tomorrow = today.plusDays(1);
    
    assertThat(today, is(lessThan(tomorrow)));
}

ステートメントassertThat(today、is(lessThan(tomorrow)))が通常の英語に近いのはとてもうれしいことです。

4.4. カスタムクラスesでマッチャーを注文する

では、独自のクラスを作成して Compareableを実装してみませんか?こうすることで、オーダーマッチャーを活用してカスタムオーダールールで使用できます。

Personbeanを作成することから始めましょう。

public class Person {
    String name;
    int age;

    // standard constructor, getters and setters
}

それでは、Compareableを実装しましょう。

public class Person implements Comparable<Person> {
        
    // ...

    @Override
    public int compareTo(Person o) {
        if (this.age == o.getAge()) return 0;
        if (this.age > o.getAge()) return 1;
        else return -1;
    }
}

compareTo の実装では、2人の年齢を比較します。 次に、いくつかの新しいテストを作成しましょう。

@Test
public void givenAmanda_whenOlderThanBenjamin_thenCorrect() {
    Person amanda = new Person("Amanda", 20);
    Person benjamin = new Person("Benjamin", 18);
 
    assertThat(amanda, is(greaterThan(benjamin)));
}

@Test
public void 
givenBenjamin_whenYoungerThanAmanda_thenCorrect() {
    Person amanda = new Person("Amanda", 20);
    Person benjamin = new Person("Benjamin", 18);
 
    assertThat(benjamin, is(lessThan(amanda)));
}

マッチャーは、compareToロジックに基づいて機能するようになります。

5. NaNマッチャー

Hamcrestは、 1つの追加の数値マッチャーを提供して、数値が実際に数値ではないかどうかを定義します

@Test
public void givenNaN_whenIsNotANumber_thenCorrect() {
    double zero = 0d;
    
    assertThat(zero / zero, is(notANumber()));
}

6. 結論

ご覧のとおり、番号マッチャーは、一般的なアサーションを単純化するのに非常に役立ちます。

さらに、一般的なハムクレストマッチャーは、わかりやすく、読みやすいです。

これらすべてに加えて、マッチャーをカスタム比較ロジックと組み合わせる機能により、マッチャーはほとんどのプロジェクトにとって強力なツールになります。

この記事の例の完全な実装は、GitHubにあります。