AssertJを使ったカスタムアサーション

AssertJを使用したカスタムアサーション

 

1. 概要

このチュートリアルでは、カスタムAssertJアサーションの作成について説明します。 AssertJの基本can be found here.

簡単に言えば、カスタムアサーションを使用すると、独自のクラスに固有のアサーションを作成でき、テストでドメインモデルをより適切に反映できます。

2. テスト対象のクラス

このチュートリアルのテストケースは、Personクラスを中心に構築されます。

public class Person {
    private String fullName;
    private int age;
    private List nicknames;

    public Person(String fullName, int age) {
        this.fullName = fullName;
        this.age = age;
        this.nicknames = new ArrayList<>();
    }

    public void addNickname(String nickname) {
        nicknames.add(nickname);
    }

    // getters
}

3. カスタムアサーションクラス

カスタムAssertJアサーションクラスの記述は非常に簡単です。 All we need to do is to declare a class that extends AbstractAssert, add a required constructor, and provide custom assertion methods.

アサーションクラスは、isNotNullisEqualToなどのAPIの重要なアサーションメソッドにアクセスできるように、AbstractAssertクラスを拡張する必要があります。

Personのカスタムアサーションクラスのスケルトンは次のとおりです。

public class PersonAssert extends AbstractAssert {

    public PersonAssert(Person actual) {
        super(actual, PersonAssert.class);
    }

    // assertion methods described later
}

AbstractAssertクラスを拡張するときは、2つの型引数を指定する必要があります。1つはメソッドチェーンに必要なカスタムアサーションクラス自体で、もう1つはテスト中のクラスです。

アサーションクラスへのエントリポイントを提供するために、アサーションチェーンを開始するために使用できる静的メソッドを定義できます。

public static PersonAssert assertThat(Person actual) {
    return new PersonAssert(actual);
}

次に、PersonAssertクラスに含まれるいくつかのカスタムアサーションについて説明します。

最初のメソッドは、PersonのフルネームがString引数と一致することを確認します。

public PersonAssert hasFullName(String fullName) {
    isNotNull();
    if (!actual.getFullName().equals(fullName)) {
        failWithMessage("Expected person to have full name %s but was %s",
          fullName, actual.getFullName());
    }
    return this;
}

次のメソッドは、ageに基づいてPersonが成人であるかどうかをテストします。

public PersonAssert isAdult() {
    isNotNull();
    if (actual.getAge() < 18) {
        failWithMessage("Expected person to be adult");
    }
    return this;
}

最後に、nicknameの存在を確認します。

public PersonAssert hasNickName(String nickName) {
    isNotNull();
    if (!actual.getNickNames().contains(nickName)) {
        failWithMessage("Expected person to have nickname %s",
          nickName);
    }
    return this;
}

複数のカスタムアサーションクラスがある場合、すべてのassertThatメソッドをクラスにラップして、各アサーションクラスに静的ファクトリメソッドを提供できます。

public class Assertions {
    public static PersonAssert assertThat(Person actual) {
        return new PersonAssert(actual);
    }

    // static factory methods of other assertion classes
}

上記のAssertionsクラスは、すべてのカスタムアサーションクラスへの便利なエントリポイントです。

このクラスの静的メソッドは同じ名前を持ち、パラメータタイプによって互いに区別されます。

4. 実行中

次のテストケースでは、前のセクションで作成したカスタムアサーションメソッドを示します。 assertThatメソッドは、コアのAssertJ APIではなく、カスタムAssertionsクラスからインポートされることに注意してください。

hasFullNameメソッドの使用方法は次のとおりです。

@Test
public void whenPersonNameMatches_thenCorrect() {
    Person person = new Person("John Doe", 20);
    assertThat(person)
      .hasFullName("John Doe");
}

これは、isAdultメソッドを示すネガティブテストケースです。

@Test
public void whenPersonAgeLessThanEighteen_thenNotAdult() {
    Person person = new Person("Jane Roe", 16);

    // assertion fails
    assertThat(person).isAdult();
}

hasNicknameメソッドを示す別のテスト:

@Test
public void whenPersonDoesNotHaveAMatchingNickname_thenIncorrect() {
    Person person = new Person("John Doe", 20);
    person.addNickname("Nick");

    // assertion will fail
    assertThat(person)
      .hasNickname("John");
}

5. アサーションジェネレータ

オブジェクトモデルに対応するカスタムアサーションクラスを作成すると、非常に読みやすいテストケースへの道が開かれます。

However, if we have a lot of classes, it would be painful to manually create custom assertion classes for all of them。 これがAssertJアサーションジェネレーターの出番です。

Mavenでアサーションジェネレーターを使用するには、pom.xmlファイルにプラグインを追加する必要があります。


    org.assertj
    assertj-assertions-generator-maven-plugin
    2.1.0
    
        
            com.example.testing.assertj.custom.Person
        
    

assertj-assertions-generator-maven-pluginの最新バージョンはhereにあります。

上記のプラグインのclasses要素は、アサーションを生成するクラスをマークします。 プラグインの他の構成については、this postを参照してください。

The AssertJ assertions generator creates assertions for each public property of the target class。 各アサーションメソッドの具体的な名前は、フィールドまたはプロパティのタイプによって異なります。 アサーションジェネレータの完全な説明については、this referenceを確認してください。

プロジェクトのベースディレクトリで次のMavenコマンドを実行します。

mvn assertj:generate-assertions

フォルダtarget/generated-test-sources/assertj-assertions. For example,に生成されたアサーションクラスが表示されます。生成されたアサーションのエントリポイントクラスは次のようになります。

// generated comments are stripped off for brevity

package com.example.testing.assertj.custom;

@javax.annotation.Generated(value="assertj-assertions-generator")
public class Assertions {

    @org.assertj.core.util.CheckReturnValue
    public static com.example.testing.assertj.custom.PersonAssert
      assertThat(com.example.testing.assertj.custom.Person actual) {
        return new com.example.testing.assertj.custom.PersonAssert(actual);
    }

    protected Assertions() {
        // empty
    }
}

これで、生成されたソースファイルをテストディレクトリにコピーし、テスト要件を満たすためにカスタムアサーションメソッドを追加できます。

注意すべき重要な点の1つは、生成されたコードが完全に正しいとは限らないことです。 現時点では、ジェネレーターは完成品ではなく、コミュニティが取り組んでいます。

したがって、ジェネレーターを当たり前のように考えるのではなく、生活を楽にする支援ツールとしてジェネレーターを使用する必要があります。

6. 結論

このチュートリアルでは、AssertJライブラリを使用して手動と自動の両方で読み取り可能なテストコードを作成するためのカスタムアサーションを作成する方法を示しました。

テスト対象のクラスが少数の場合は、手動のソリューションで十分です。それ以外の場合は、ジェネレーターを使用する必要があります。

そして、いつものように、すべての例とコードスニペットの実装はover on GitHubで見つけることができます。