1. 概要

JUnit 5は、テストクラスとテストメソッド名のカスタマイズを適切にサポートしています。 このクイックチュートリアルでは、@DisplayNameGenerationアノテーションを介してJUnit5カスタム表示名ジェネレーターを使用する方法を説明します。

2. 表示名の生成

@DisplayNameGenerationアノテーションを介してカスタム表示名ジェネレーターを構成できます。 ただし、@DisplayNameアノテーションは常にどの表示名ジェネレーターよりも優先されることに注意してください。

まず、JUnit 5は、名前のアンダースコアをスペースに置き換えるDisplayNameGenerator.ReplaceUnderscoresクラスを提供します。 例を見てみましょう:

@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
class ReplaceUnderscoresGeneratorUnitTest {

    @Nested
    class when_doing_something {

        @Test
        void then_something_should_happen() {
        }

        @Test
        @DisplayName("@DisplayName takes precedence over generation")
        void override_generator() {
        }
    }
}

これで、テストを実行すると、表示名の生成によってテスト出力が読みやすくなっていることがわかります。

└─ ReplaceUnderscoresGeneratorUnitTest ✓
   └─ when doing something ✓
      ├─ then something should happen() ✓
      └─ @DisplayName takes precedence over generation ✓

3. カスタム表示名ジェネレータ

カスタム表示名ジェネレーターを作成するには、DisplayNameGeneratorインターフェースのメソッドを実装するクラスを作成する必要があります。 インターフェイスには、クラスの名前を生成するためのメソッド、ネストされたクラス、およびメソッドがあります。

3.1. キャメルケースの交換

キャメルケースの名前を読みやすい文に置き換える簡単な表示名ジェネレーターから始めましょう。 まず、DisplayNameGenerator.Standardクラス拡張できます。

    static class ReplaceCamelCase extends DisplayNameGenerator.Standard {
        @Override
        public String generateDisplayNameForClass(Class<?> testClass) {
            return replaceCamelCase(super.generateDisplayNameForClass(testClass));
        }

        @Override
        public String generateDisplayNameForNestedClass(Class<?> nestedClass) {
            return replaceCamelCase(super.generateDisplayNameForNestedClass(nestedClass));
        }

        @Override
        public String generateDisplayNameForMethod(Class<?> testClass, Method testMethod) {
            return this.replaceCamelCase(testMethod.getName()) + 
              DisplayNameGenerator.parameterTypesAsString(testMethod);
        }

        String replaceCamelCase(String camelCase) {
            StringBuilder result = new StringBuilder();
            result.append(camelCase.charAt(0));
            for (int i=1; i<camelCase.length(); i++) {
                if (Character.isUpperCase(camelCase.charAt(i))) {
                    result.append(' ');
                    result.append(Character.toLowerCase(camelCase.charAt(i)));
                } else {
                    result.append(camelCase.charAt(i));
                }
            }
            return result.toString();
        }
    }

上記の例では、表示名のさまざまな部分を生成するメソッドを確認できます。

ジェネレーターのテストを書いてみましょう。

@DisplayNameGeneration(DisplayNameGeneratorUnitTest.ReplaceCamelCase.class)
class DisplayNameGeneratorUnitTest {

    @Test
    void camelCaseName() {
    }
}

次に、テストを実行すると、キャメルケース名が読み取り可能な文に置き換えられていることがわかります。

└─ Display name generator unit test ✓
   └─ camel case name() ✓

3.2. 指示文

これまで、非常に単純なユースケースについて説明してきました。 ただし、よりクリエイティブにすることができます。

    static class IndicativeSentences extends ReplaceCamelCase {
        @Override
        public String generateDisplayNameForNestedClass(Class<?> nestedClass) {
            return super.generateDisplayNameForNestedClass(nestedClass) + "...";
        }

        @Override
        public String generateDisplayNameForMethod(Class<?> testClass, Method testMethod) {
            return replaceCamelCase(testClass.getSimpleName() + " " + testMethod.getName()) + ".";
        }
    }

ここでの考え方は、ネストされたクラスとテストメソッドから指示文を作成することです。 つまり、ネストされたクラス名がテストメソッド名の前に追加されます。

class DisplayNameGeneratorUnitTest {

    @Nested
    @DisplayNameGeneration(DisplayNameGeneratorUnitTest.IndicativeSentences.class)
    class ANumberIsFizz {
        @Test
        void ifItIsDivisibleByThree() {
        }

        @ParameterizedTest(name = "Number {0} is fizz.")
        @ValueSource(ints = { 3, 12, 18 })
        void ifItIsOneOfTheFollowingNumbers(int number) {
        }
    }

    @Nested
    @DisplayNameGeneration(DisplayNameGeneratorUnitTest.IndicativeSentences.class)
    class ANumberIsBuzz {
        @Test
        void ifItIsDivisibleByFive() {
        }

        @ParameterizedTest(name = "Number {0} is buzz.")
        @ValueSource(ints = { 5, 10, 20 })
        void ifItIsOneOfTheFollowingNumbers(int number) {
        }
    }
}

例を見ると、ネストされたクラスをテストメソッドのコンテキストとして使用しています。 結果をわかりやすく説明するために、テストを実行してみましょう。

└─ Display name generator unit test ✓
   ├─ A number is buzz... ✓
   │  ├─ A number is buzz if it is one of the following numbers. ✓
   │  │  ├─ Number 5 is buzz. ✓
   │  │  ├─ Number 10 is buzz. ✓
   │  │  └─ Number 20 is buzz. ✓
   │  └─ A number is buzz if it is divisible by five. ✓
   └─ A number is fizz... ✓
      ├─ A number is fizz if it is one of the following numbers. ✓
      │  ├─ Number 3 is fizz. ✓
      │  ├─ Number 12 is fizz. ✓
      │  └─ Number 18 is fizz. ✓
      └─ A number is fizz if it is divisible by three. ✓

ご覧のとおり、ジェネレーターはネストされたクラス名とテストメソッド名を組み合わせて指示文を作成しました。

4. 結論

このチュートリアルでは、@ DisplayNameGenerationアノテーションを使用してテストの表示名を生成する方法を説明しました。 さらに、表示名の生成をカスタマイズするために、独自のDisplayNameGeneratorを作成しました。

いつものように、この記事で使用されている例は、GitHubプロジェクトにあります。