Hamcrestによるテスト

Hamcrestを使用したテスト

1. 概要

Hamcrestは、Javaエコシステムでの単体テストに使用されるよく知られたフレームワークです。 これはJUnitにバンドルされており、簡単に言えば、アサーションを作成するために、マッチャークラスと呼ばれる既存の述語を使用します。

このチュートリアルでは、explore the Hamcrest APIを使用して、それを利用してソフトウェアのより簡潔で直感的な単体テストを作成する方法を学習します。

2. ハムクレストのセットアップ

pom.xmlファイルに次の依存関係を追加することで、mavenでHamcrestを使用できます。


    org.hamcrest
    hamcrest-all
    1.3

このライブラリの最新バージョンは常にhereで見つけることができます。

3. テスト例

Hamcrestは、アサーションを作成するためにjunitおよびその他のテストフレームワークで一般的に使用されます。 具体的には、junitの多数のassertメソッドを使用する代わりに、適切なマッチャーを使用したAPIの単一のassertThatステートメントのみを使用します。

ケースに関係なく、2つのStringsが等しいかどうかをテストする例を見てみましょう。 これにより、Hamcrestがテスト方法にどのように適合するかについて明確なアイデアが得られるはずです。

public class StringMatcherTest {

    @Test
    public void given2Strings_whenEqual_thenCorrect() {
        String a = "foo";
        String b = "FOO";
        assertThat(a, equalToIgnoringCase(b));
    }
}

次のセクションでは、Hamcrestが提供する他のいくつかの一般的なマッチャーを見ていきます。

4. Objectマッチャー

Hamcrestは、任意のJavaオブジェクトに対してアサーションを作成するためのマッチャーを提供します。

ObjecttoStringメソッドが指定されたStringを返すことを表明するには:

@Test
public void givenBean_whenToStringReturnsRequiredString_thenCorrect(){
    Person person=new Person("Barrack", "Washington");
    String str=person.toString();
    assertThat(person,hasToString(str));
}

あるクラスが別のクラスのサブクラスであることも確認できます。

@Test
public void given2Classes_whenOneInheritsFromOther_thenCorrect(){
        assertThat(Cat.class,typeCompatibleWith(Animal.class));
    }
}

5. Beanマッチャー

HamcrestのBeanマッチャーを使用して、JavaBeanのプロパティを検査できます。

次のPersonBeanを想定します。

public class Person {
    String name;
    String address;

    public Person(String personName, String personAddress) {
        name = personName;
        address = personAddress;
    }
}

Beanに次のようなプロパティnameがあるかどうかを確認できます。

@Test
public void givenBean_whenHasValue_thenCorrect() {
    Person person = new Person("example", 25);
    assertThat(person, hasProperty("name"));
}

また、Personにニューヨークに初期化されたaddressプロパティがあるかどうかを確認することもできます。

@Test
public void givenBean_whenHasCorrectValue_thenCorrect() {
    Person person = new Person("example", "New York");
    assertThat(person, hasProperty("address", equalTo("New York")));
}

2つのPersonオブジェクトが同じ値で作成されているかどうかを確認することもできます。

@Test
public void given2Beans_whenHavingSameValues_thenCorrect() {
    Person person1 = new Person("example", "New York");
    Person person2 = new Person("example", "New York");
    assertThat(person1, samePropertyValuesAs(person2));
}

6. Collectionマッチャー

Hamcrestは、Collectionsを検査するためのマッチャーを提供します。

Collectionが空かどうかを確認する簡単なチェック:

@Test
public void givenCollection_whenEmpty_thenCorrect() {
    List emptyList = new ArrayList<>();
    assertThat(emptyList, empty());
}

Collection:のサイズを確認するには

@Test
public void givenAList_whenChecksSize_thenCorrect() {
    List hamcrestMatchers = Arrays.asList(
      "collections", "beans", "text", "number");
    assertThat(hamcrestMatchers, hasSize(4));
}

配列に必要なサイズがあることをアサートするためにも使用できます。

@Test
public void givenArray_whenChecksSize_thenCorrect() {
    String[] hamcrestMatchers = { "collections", "beans", "text", "number" };
    assertThat(hamcrestMatchers, arrayWithSize(4));
}

順序に関係なく、Collectionに特定のメンバーが含まれているかどうかを確認するには:

@Test
public void givenAListAndValues_whenChecksListForGivenValues_thenCorrect() {
    List hamcrestMatchers = Arrays.asList(
      "collections", "beans", "text", "number");
    assertThat(hamcrestMatchers,
    containsInAnyOrder("beans", "text", "collections", "number"));
}

Collectionメンバーが指定された順序であることをさらに主張するには:

@Test
public void givenAListAndValues_whenChecksListForGivenValuesWithOrder_thenCorrect() {
    List hamcrestMatchers = Arrays.asList(
      "collections", "beans", "text", "number");
    assertThat(hamcrestMatchers,
    contains("collections", "beans", "text", "number"));
}

配列に特定の要素が1つだけあるかどうかを確認するには:

@Test
public void givenArrayAndValue_whenValueFoundInArray_thenCorrect() {
    String[] hamcrestMatchers = { "collections", "beans", "text", "number" };
    assertThat(hamcrestMatchers, hasItemInArray("text"));
}

同じテストに代替マッチャーを使用することもできます。

@Test
public void givenValueAndArray_whenValueIsOneOfArrayElements_thenCorrect() {
    String[] hamcrestMatchers = { "collections", "beans", "text", "number" };
    assertThat("text", isOneOf(hamcrestMatchers));
}

または、次のように別のマッチャーで同じことを実行できます。

@Test
public void givenValueAndArray_whenValueFoundInArray_thenCorrect() {
    String[] array = new String[] { "collections", "beans", "text",
      "number" };
    assertThat("beans", isIn(array));
}

また、順序に関係なく、配列に特定の要素が含まれているかどうかを確認できます。

@Test
public void givenArrayAndValues_whenValuesFoundInArray_thenCorrect() {
    String[] hamcrestMatchers = { "collections", "beans", "text", "number" };
      assertThat(hamcrestMatchers,
    arrayContainingInAnyOrder("beans", "collections", "number",
      "text"));
}

配列に指定された要素が指定された順序で含まれているかどうかを確認するには:

@Test
public void givenArrayAndValues_whenValuesFoundInArrayInOrder_thenCorrect() {
    String[] hamcrestMatchers = { "collections", "beans", "text", "number" };
    assertThat(hamcrestMatchers,
    arrayContaining("collections", "beans", "text", "number"));
}

CollectionMap,の場合、これらのそれぞれの関数で次のマッチャーを使用できます。

指定されたキーが含まれているかどうかを確認するには:

@Test
public void givenMapAndKey_whenKeyFoundInMap_thenCorrect() {
    Map map = new HashMap<>();
    map.put("blogname", "example");
    assertThat(map, hasKey("blogname"));
}

そして与えられた値:

@Test
public void givenMapAndValue_whenValueFoundInMap_thenCorrect() {
    Map map = new HashMap<>();
    map.put("blogname", "example");
    assertThat(map, hasValue("example"));
}

そして最後に、所定のエントリ(キー、値):

@Test
public void givenMapAndEntry_whenEntryFoundInMap_thenCorrect() {
    Map map = new HashMap<>();
    map.put("blogname", "example");
    assertThat(map, hasEntry("blogname", "example"));
}

7. Numberマッチャー

Numberマッチャーは、Numberクラスの変数に対してアサーションを実行するために使用されます。

greaterThanの状態を確認するには:

@Test
public void givenAnInteger_whenGreaterThan0_thenCorrect() {
    assertThat(1, greaterThan(0));
}

greaterThanまたはequalToの状態を確認するには:

@Test
public void givenAnInteger_whenGreaterThanOrEqTo5_thenCorrect() {
    assertThat(5, greaterThanOrEqualTo(5));
}

lessThanの状態を確認するには:

@Test
public void givenAnInteger_whenLessThan0_thenCorrect() {
    assertThat(-1, lessThan(0));
}

lessThanまたはequalToの状態を確認するには:

@Test
public void givenAnInteger_whenLessThanOrEqTo5_thenCorrect() {
    assertThat(-1, lessThanOrEqualTo(5));
}

closeToの状態を確認するには:

@Test
public void givenADouble_whenCloseTo_thenCorrect() {
    assertThat(1.2, closeTo(1, 0.5));
}

最後のマッチャーcloseTo.に細心の注意を払いましょう。最初の引数であるオペランドはターゲットが比較される引数であり、2番目の引数はオペランド.からの許容偏差です。ターゲットがオペランド+偏差またはオペランド偏差の場合、テストは合格です。

8. テキストマッチャー

Stringsのアサーションは、Hamcrestのテキストマッチャーを使用すると、より簡単に、より簡潔に、より直感的になります。 このセクションでそれらを見ていきます。

Stringが空かどうかを確認するには:

@Test
public void givenString_whenEmpty_thenCorrect() {
    String str = "";
    assertThat(str, isEmptyString());
}

Stringが空かnullかを確認するには:

@Test
public void givenString_whenEmptyOrNull_thenCorrect() {
    String str = null;
    assertThat(str, isEmptyOrNullString());
}

空白を無視して2つのStringsが等しいかどうかを確認するには:

@Test
public void given2Strings_whenEqualRegardlessWhiteSpace_thenCorrect() {
    String str1 = "text";
    String str2 = " text ";
    assertThat(str1, equalToIgnoringWhiteSpace(str2));
}

また、特定のStringに、特定の順序で1つ以上のサブ文字列が存在するかどうかを確認することもできます。

@Test
public void givenString_whenContainsGivenSubstring_thenCorrect() {
    String str = "calligraphy";
    assertThat(str, stringContainsInOrder(Arrays.asList("call", "graph")));
}

最後に、大文字と小文字に関係なく、2つのStringsが等しいかどうかを確認できます。

@Test
 public void given2Strings_whenEqual_thenCorrect() {
    String a = "foo";
    String b = "FOO";
    assertThat(a, equalToIgnoringCase(b));
}

9. コアAPI

HamcrestコアAPIは、サードパーティのフレームワークプロバイダーによって使用されます。 ただし、ユニットテストを読みやすくするための優れた構造と、同じように簡単に使用できるコアマッチャーを提供します。

マッチャーのis構成による可読性:

@Test
public void given2Strings_whenIsEqualRegardlessWhiteSpace_thenCorrect() {
    String str1 = "text";
    String str2 = " text ";
    assertThat(str1, is(equalToIgnoringWhiteSpace(str2)));
}

isは、単純なデータ型で構成されます。

@Test
public void given2Strings_whenIsEqual_thenCorrect() {
    String str1 = "text";
    String str2 = "text";
    assertThat(str1, is(str2));
}

マッチャーのnot構文による否定:

@Test
public void given2Strings_whenIsNotEqualRegardlessWhiteSpace_thenCorrect() {
    String str1 = "text";
    String str2 = " texts ";
    assertThat(str1, not(equalToIgnoringWhiteSpace(str2)));
}

notは、単純なデータ型で構成されます。

@Test
public void given2Strings_whenNotEqual_thenCorrect() {
    String str1 = "text";
    String str2 = "texts";
    assertThat(str1, not(str2));
}

Stringに特定の部分文字列が含まれているかどうかを確認します。

@Test
public void givenAStrings_whenContainsAnotherGivenString_thenCorrect() {
    String str1 = "calligraphy";
    String str2 = "call";
    assertThat(str1, containsString(str2));
}

Stringが指定された部分文字列で始まるかどうかを確認します。

@Test
public void givenAString_whenStartsWithAnotherGivenString_thenCorrect() {
    String str1 = "calligraphy";
    String str2 = "call";
    assertThat(str1, startsWith(str2));
}

Stringが指定された部分文字列で終わっているかどうかを確認します。

@Test
public void givenAString_whenEndsWithAnotherGivenString_thenCorrect() {
    String str1 = "calligraphy";
    String str2 = "phy";
    assertThat(str1, endsWith(str2));
}

2つのObjectsが同じインスタンスであるかどうかを確認します。

@Test
public void given2Objects_whenSameInstance_thenCorrect() {
    Cat cat=new Cat();
    assertThat(cat, sameInstance(cat));
}

Objectが特定のクラスのインスタンスであるかどうかを確認します。

@Test
public void givenAnObject_whenInstanceOfGivenClass_thenCorrect() {
    Cat cat=new Cat();
    assertThat(cat, instanceOf(Cat.class));
}

Collectionのすべてのメンバーが条件を満たすかどうかを確認します。

@Test
public void givenList_whenEachElementGreaterThan0_thenCorrect() {
    List list = Arrays.asList(1, 2, 3);
    int baseCase = 0;
    assertThat(list, everyItem(greaterThan(baseCase)));
}

Stringnullではないことを確認します。

@Test
public void givenString_whenNotNull_thenCorrect() {
    String str = "notnull";
    assertThat(str, notNullValue());
}

条件を一緒にチェーンし、論理ORと同様に、ターゲットが条件のいずれかを満たす場合にテストが合格します。

@Test
public void givenString_whenMeetsAnyOfGivenConditions_thenCorrect() {
    String str = "calligraphy";
    String start = "call";
    String end = "foo";
    assertThat(str, anyOf(startsWith(start), containsString(end)));
}

条件を連結し、論理ANDと同様に、ターゲットがすべての条件を満たしている場合にのみテストが合格します。

@Test
public void givenString_whenMeetsAllOfGivenConditions_thenCorrect() {
    String str = "calligraphy";
    String start = "call";
    String end = "phy";
    assertThat(str, allOf(startsWith(start), endsWith(end)));
}

10. カスタムマッチャー

TypeSafeMatcherを拡張することにより、独自のマッチャーを定義できます。 このセクションでは、ターゲットが正の整数である場合にのみテストに合格するカスタムマッチャーを作成します。

public class IsPositiveInteger extends TypeSafeMatcher {

    public void describeTo(Description description) {
        description.appendText("a positive integer");
    }

    @Factory
    public static Matcher isAPositiveInteger() {
        return new IsPositiveInteger();
    }

    @Override
    protected boolean matchesSafely(Integer integer) {
        return integer > 0;
    }

}

ターゲットが実際に正の整数であることを確認するmatchSafelyメソッドと、テストに合格しなかった場合に失敗メッセージを生成するdescribeToメソッドを実装するだけで済みます。

新しいカスタムマッチャーを使用するテストは次のとおりです。

@Test
public void givenInteger_whenAPositiveValue_thenCorrect() {
    int num = 1;
    assertThat(num, isAPositiveInteger());
}

そして、正でない整数を渡したために表示される失敗メッセージは次のとおりです。

java.lang.AssertionError: Expected: a positive integer but: was <-1>

11. 結論

このチュートリアルでは、explored the Hamcrest APIを使用して、より優れた、より保守しやすい単体テストを作成する方法を学びました。

これらすべての例とコードスニペットの完全な実装can be found in my Hamcrest github project.