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 .