1. Обзор
При модульном тестировании мы можем периодически обрабатывать результаты выполнения наших тестовых методов. В этом кратком руководстве мы рассмотрим, как это можно сделать с помощью TestWatcher API, предоставляемого JUnit .
Чтобы получить подробное руководство по тестированию с помощью JUnit, ознакомьтесь с нашим превосходным руководством по JUnit 5 .
2. API TestWatcher
Короче говоря, интерфейс TestWatcher
определяет API для расширений , которые хотят обрабатывать результаты тестов . Один из способов, которым мы можем думать об этом API, — это предоставление хуков для получения статуса отдельного тестового примера.
Но, прежде чем мы углубимся в некоторые реальные примеры, давайте сделаем шаг назад и кратко подытожим методы в интерфейсе TestWatcher
:
testAborted(ExtensionContext context, Throwable cause)
Чтобы обработать результаты прерванного теста, мы можем переопределить метод testAborted
. Как следует из названия, этот метод вызывается после прерывания теста.
testDisabled(ExtensionContext context, Optional reason)
Мы можем переопределить метод testDisabled
, когда хотим обработать результаты отключенного метода тестирования. Этот метод также может включать в себя причину отключения теста.
testFailed(ExtensionContext context, Throwable cause)
Если мы хотим выполнить некоторую дополнительную обработку после сбоя теста, мы можем просто реализовать функциональность в методе testFailed
. Этот метод может включать в себя причину отказа теста.
testSuccessful(ExtensionContext context)
И последнее, но не менее важное: когда мы хотим обработать результаты успешного теста, мы просто переопределяем метод testSuccessful
.
Следует отметить, что все методы содержат ExtensionContext
. Это инкапсулирует контекст, в котором выполняется текущий тест.
3. Зависимости Maven
Прежде всего, давайте добавим зависимости проекта, которые нам понадобятся для наших примеров.
Помимо основной библиотеки JUnit 5 junit-jupiter-engine
, нам также понадобится библиотека junit- jupiter-api
:
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.8.1</version>
<scope>test</scope>
</dependency>
Как всегда, последнюю версию мы можем получить с Maven Central .
4. Пример TestResultLoggerExtension
Теперь, когда у нас есть общее представление об API TestWatcher
, мы рассмотрим практический пример.
Давайте начнем с создания простого расширения для регистрации результатов и предоставления сводки наших тестов . В этом случае для создания расширения нам нужно определить класс, реализующий интерфейс TestWatcher
:
public class TestResultLoggerExtension implements TestWatcher, AfterAllCallback {
private List<TestResultStatus> testResultsStatus = new ArrayList<>();
private enum TestResultStatus {
SUCCESSFUL, ABORTED, FAILED, DISABLED;
}
//...
}
Как и все интерфейсы расширения, интерфейс TestWatcher
также расширяет основной интерфейс Extension
, который является лишь интерфейсом маркера. В этом примере мы также реализуем интерфейс AfterAllCallback
.
В нашем расширении у нас есть список TestResultStatus
, который представляет собой простое перечисление, которое мы собираемся использовать для представления статуса результата теста.
4.1. Обработка результатов теста
Теперь давайте посмотрим, как обработать результаты отдельного метода модульного тестирования:
@Override
public void testDisabled(ExtensionContext context, Optional<String> reason) {
LOG.info("Test Disabled for test {}: with reason :- {}",
context.getDisplayName(),
reason.orElse("No reason"));
testResultsStatus.add(TestResultStatus.DISABLED);
}
@Override
public void testSuccessful(ExtensionContext context) {
LOG.info("Test Successful for test {}: ", context.getDisplayName());
testResultsStatus.add(TestResultStatus.SUCCESSFUL);
}
Начнем с заполнения тела нашего расширения и переопределения методов testDisabled()
и testSuccessful()
.
В нашем тривиальном примере мы выводим имя теста и добавляем статус теста в список testResultsStatus
.
Мы продолжим в том же духе для двух других методов — testAborted()
и testFailed()
:
@Override
public void testAborted(ExtensionContext context, Throwable cause) {
LOG.info("Test Aborted for test {}: ", context.getDisplayName());
testResultsStatus.add(TestResultStatus.ABORTED);
}
@Override
public void testFailed(ExtensionContext context, Throwable cause) {
LOG.info("Test Failed for test {}: ", context.getDisplayName());
testResultsStatus.add(TestResultStatus.FAILED);
}
4.2. Подведение итогов испытаний
В последней части нашего примера мы переопределим метод afterAll ()
:
@Override
public void afterAll(ExtensionContext context) throws Exception {
Map<TestResultStatus, Long> summary = testResultsStatus.stream()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
LOG.info("Test result summary for {} {}", context.getDisplayName(), summary.toString());
}
Чтобы быстро напомнить, метод afterAll
выполняется после того, как все тестовые методы были запущены. Мы используем этот метод, чтобы сгруппировать различные TestResultStatus
, которые у нас есть в списке результатов теста, перед выводом очень простой сводки.
Чтобы получить подробное руководство по обратным вызовам жизненного цикла, ознакомьтесь с нашим превосходным руководством по расширениям JUnit 5 .
5. Запуск тестов
В этом предпоследнем разделе мы увидим, как выглядят результаты наших тестов с использованием нашего простого расширения ведения журнала.
Теперь, когда мы определили наше расширение, мы сначала зарегистрируем его, используя стандартную аннотацию @ExtendWith
:
@ExtendWith(TestResultLoggerExtension.class)
class TestWatcherAPIUnitTest {
@Test
void givenFalseIsTrue_whenTestAbortedThenCaptureResult() {
Assumptions.assumeTrue(false);
}
@Disabled
@Test
void givenTrueIsTrue_whenTestDisabledThenCaptureResult() {
Assert.assertTrue(true);
}
//...
Затем мы заполняем наш тестовый класс модульными тестами, добавляя смесь отключенных, прерванных и успешных тестов.
5.1. Просмотр вывода
Когда мы запускаем модульный тест, мы должны увидеть вывод для каждого теста:
INFO c.b.e.t.TestResultLoggerExtension -
Test Successful for test givenTrueIsTrue_whenTestAbortedThenCaptureResult()
...
Test result summary for TestWatcherAPIUnitTest {ABORTED=1, SUCCESSFUL=1, DISABLED=2}
Естественно, мы также увидим напечатанную сводку, когда все методы тестирования будут завершены.
6. Гочки
В этом последнем разделе давайте рассмотрим пару тонкостей, о которых следует помнить при работе с интерфейсом TestWatcher
:
- Расширениям TestWatcher не разрешается влиять на выполнение тестов; это означает , что если исключение выдается из
TestWatcher
, оно не будет распространяться до работающего теста. - В настоящее время этот API используется только для отчетов о результатах методов
@Test
и@TestTemplate.
- По умолчанию, если для метода
testDisabled
не указана причина , то он будет содержать полное имя метода тестирования, за которым следует 'is @Disabled
'
7. Заключение
Подводя итог, в этом руководстве мы показали, как мы можем использовать JUnit 5 TestWatcher
API для обработки результатов выполнения наших тестовых методов.
Полный исходный код примеров можно найти на GitHub .