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

Модульное тестирование System.out.println() с помощью JUnit

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

1. Обзор

При модульном тестировании мы можем иногда захотеть протестировать сообщения, которые мы пишем в стандартный вывод через System.out.println() .

Хотя обычно мы предпочитаем структуру протоколирования прямому взаимодействию со стандартным выводом, иногда это невозможно.

В этом кратком руководстве мы рассмотрим несколько способов модульного тестирования System.out.println() с помощью JUnit .

2. Простой метод печати

На протяжении всего этого руководства в центре внимания наших тестов будет простой метод, который записывает в стандартный поток вывода:

private void print(String output) {
System.out.println(output);
}

Быстрое напоминание о том, что переменная out является общедоступным статическим окончательным объектом PrintStream, который представляет стандартный поток вывода, предназначенный для общесистемного использования.

3. Работа с ядром Java

Теперь давайте посмотрим, как мы можем написать модульный тест для проверки содержимого того, что мы отправляем методу println . Однако, прежде чем мы напишем наш фактический модульный тест, нам нужно обеспечить некоторую инициализацию в нашем тесте:

private final PrintStream standardOut = System.out;
private final ByteArrayOutputStream outputStreamCaptor = new ByteArrayOutputStream();

@BeforeEach
public void setUp() {
System.setOut(new PrintStream(outputStreamCaptor));
}

В методе setUp мы переназначаем стандартный поток вывода новому PrintStream с помощью ByteArrayOutputStream . Как мы увидим, этот выходной поток — это место, где теперь будут напечатаны значения:

@Test
void givenSystemOutRedirection_whenInvokePrintln_thenOutputCaptorSuccess() {
print("Hello ForEach Readers!!");

Assert.assertEquals("Hello ForEach Readers!!", outputStreamCaptor.toString()
.trim());
}

После вызова метода печати с выбранным текстом мы можем убедиться, что outputStreamCaptor содержит ожидаемое содержимое. Мы вызываем метод trim , чтобы удалить новую строку, которую добавляет System.out.println() .

Поскольку стандартный поток вывода является общим статическим ресурсом, используемым другими частями системы, мы должны позаботиться о его восстановлении до исходного состояния после завершения нашего теста:

@AfterEach
public void tearDown() {
System.setOut(standardOut);
}

Это гарантирует, что мы не получим никаких нежелательных побочных эффектов позже в других тестах.

4. Использование системных правил

В этом разделе мы рассмотрим удобную внешнюю библиотеку под названием System Rules , которая предоставляет набор правил JUnit для тестирования кода, использующего класс System .

Давайте начнем с добавления зависимости в наш pom.xml :

<dependency>
<groupId>com.github.stefanbirkner</groupId>
<artifactId>system-rules</artifactId>
<version>1.19.0</version>
<scope>test</scope>
</dependency>

Теперь мы можем продолжить и написать тест, используя SystemOutRule , который предоставляет библиотека:

@Rule
public final SystemOutRule systemOutRule = new SystemOutRule().enableLog();

@Test
public void givenSystemOutRule_whenInvokePrintln_thenLogSuccess() {
print("Hello ForEach Readers!!");

Assert.assertEquals("Hello ForEach Readers!!", systemOutRule.getLog()
.trim());
}

Довольно круто! Используя SystemOutRule, мы можем перехватывать записи в System.out . Во- первых, мы начинаем регистрировать все, что пишется в System.out , вызывая метод enableLog в нашем правиле. Затем мы просто вызываем getLog , чтобы получить текст, записанный в System.out , так как мы вызвали enableLog .

Это правило также включает удобный метод, который возвращает журнал, в котором разделитель строк всегда равен \n .

Assert.assertEquals("Hello ForEach Readers!!\n", systemOutRule.getLogWithNormalizedLineSeparator());

5. Использование системных правил с JUnit5 и Lambdas

В JUnit5 модель правил была заменена расширениями . К счастью, библиотека системных правил, представленная в предыдущем разделе, имеет вариант , подготовленный для работы с JUnit5.

Системная лямбда доступна в Maven Central . Итак, мы можем добавить его в наш pom.xml :

<dependency>
<groupId>com.github.stefanbirkner</groupId>
<artifactId>system-lambda</artifactId>
<version>1.0.0</version>
<scope>test</scope>
</dependency>

Теперь давайте реализуем наш тест, используя эту версию библиотеки:

@Test
void givenTapSystemOut_whenInvokePrintln_thenOutputIsReturnedSuccessfully() throws Exception {

String text = tapSystemOut(() -> {
print("Hello ForEach Readers!!");
});

Assert.assertEquals("Hello ForEach Readers!!", text.trim());
}

В этой версии мы используем метод tapSystemOut , который выполняет оператор и позволяет нам захватывать содержимое, переданное в System.out .

6. Заключение

В этом руководстве мы узнали о нескольких подходах к тестированию System.out.println . В первом подходе мы увидели, как перенаправить туда, где мы записываем стандартный поток вывода, используя ядро Java.

Затем мы увидели, как использовать многообещающую внешнюю библиотеку под названием System Rules, используя сначала правила стиля JUnit 4, а затем работая с лямбда-выражениями.

Как всегда, полный исходный код статьи доступен на GitHub .