Перейти к основному содержимому

API генератора настраиваемых отображаемых имен JUnit

· 4 мин. чтения

1. Обзор

JUnit 5 имеет хорошую поддержку для настройки имен тестовых классов и тестовых методов. В этом кратком руководстве мы увидим, как мы можем использовать настраиваемые генераторы отображаемых имен JUnit 5 с помощью аннотации @DisplayNameGeneration .

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 .