API do gerador de nomes de exibição personalizados JUnit

API do gerador de nomes de exibição personalizados JUnit

1. Visão geral

O JUnit 5 possui um bom suporte para personalizar nomes de classes e métodos de teste. Neste tutorial rápido, veremos como podemos usar os geradores de nomes de exibição personalizados JUnit 5 por meio da anotação@DisplayNameGeneration.

2. Geração de nome para exibição

Podemosconfigure custom display name generators via the @DisplayNameGeneration annotation. No entanto, é bom estar ciente de que a anotação@DisplayName sempre tem precedência sobre qualquer gerador de nome de exibição.

Para começar, o JUnit 5 fornece uma classeDisplayNameGenerator.ReplaceUnderscores que substitui qualquer sublinhado nos nomes por espaços. Vamos dar uma olhada em um exemplo:

@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() {
        }
    }
}

Agora, quando executamos o teste, podemos ver que a geração do nome de exibição tornou a saída do teste mais legível:

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

3. Gerador de nome para exibição personalizado

Para escrever um gerador de nome de exibição personalizado, precisamoswrite a class that implements the methods in the DisplayNameGenerator interface. A interface possui métodos para gerar o nome para uma classe, uma classe aninhada e um método.

3.1. Substituição da caixa de camelo

Vamos começar com um gerador de nome de exibição simples que substitui nomes de caso de camelo por frases legíveis. Para começar, podemosextend the DisplayNameGenerator.Standard class:

    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

No exemplo acima, podemos ver os métodos que geram partes diferentes do nome para exibição.

Vamos escrever um teste para nosso gerador:

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

    @Test
    void camelCaseName() {
    }
}

A seguir, ao executar o teste, podemos ver quethe camel case names have been replaced with readable sentences:

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

3.2. Frases indicativas

Até agora, discutimos casos de uso muito simples. No entanto, podemos ser mais criativos:

    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()) + ".";
        }
    }

A ideia aqui écreate indicative sentences from the nested class and test method. Em outras palavras, o nome da classe aninhada será anexado ao nome do método de teste:

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

Observando o exemplo, usamos a classe aninhada como um contexto para o método de teste. Para ilustrar melhor os resultados, vamos fazer o teste:

└─ 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. ✓

Como podemos ver, o gerador combinou a classe aninhada e os nomes dos métodos de teste para criar sentenças indicativas.

4. Conclusão

Neste tutorial, vimos como usar a anotação @DisplayNameGeneration para gerar nomes de exibição para nossos testes. Além disso, escrevemos nosso próprioDisplayNameGenerator para personalizar a geração do nome de exibição.

Como de costume, os exemplos usados ​​neste artigo podem ser encontrados emGitHub project.