Тестирование вывода журнала Java Spring - PullRequest
0 голосов
/ 27 июня 2018

У меня есть приложение весенней загрузки 2, работающее на Java 10 с использованием SLF4J и входом в систему в качестве основного регистратора.

Учитывая следующий компонент пружины:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

@Service
public class MyClass {

    private static final Logger LOG = LoggerFactory.getLogger(MyClass.class);

    public void hello() {
        // more logic...
        LOG.trace("World");
    }
}

И тест, который желает проверить вывод журнала (представьте себе более сложный сценарий, в котором журнал будет содержать переменные и контекстную информацию) или факт создания сообщения журнала, считается критическим.

import org.junit.Rule;
import org.junit.Test;
import org.springframework.boot.test.rule.OutputCapture;

import static org.hamcrest.Matchers.containsString;

public class MyClassTest {

    private final MyClass myClass = new MyClass();

    @Rule
    public final OutputCapture outputCapture = new OutputCapture();

    @Test
    public void successShouldLogSuccessMessages() {
        myClass.hello();
        outputCapture.expect(containsString("World"));
    }
}

Для того, чтобы этот тест прошел, уровень лога должен быть установлен на TRACE. Я заметил непредсказуемое поведение, при котором тест либо проваливался, либо проходил в зависимости от порядка выполнения тестов - см. Кажущийся случайным сбой теста с Maven и Spring Boot 2, когда вводится WebFluxTest

Я исследовал несколько вариантов, ни один из которых не кажется «идеальным», но работает.

  1. Укажите файл конфигурации обратного входа в путь к тестовому классу, который задает уровень журнала для трассировки, по крайней мере, для этого одного класса.
  2. Установите уровень журнала этого класса равным TRACE в классе свойств приложения пружины и запустите тест в контексте пружины.
  3. Создайте настройку и разверните ее в классе теста, который программно изменяет уровень журнала во время выполнения теста, а затем сбрасывает его после.

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

@RunWith(SpringRunner.class)
@SpringBootTest(properties = "spring.profiles.active=test")
@ContextConfiguration(classes = MyClass.class)
public class MyClassTest {

    private final MyClass myClass = new MyClass();

    @Rule
    public final OutputCapture outputCapture = new OutputCapture();

    @Test
    public void successShouldLogSuccessMessages() {
        myClass.hello();
        outputCapture.expect(containsString("World"));
    }
}

Где содержание application-test.properties:

logging.level.com.example.MyClass=TRACE

Это решение работает, не требуется, чтобы я программно поигрался с регистраторами или поместил конфигурацию обратного входа в classpath, что делает все совершенно независимым от базовой структуры журналов, а сохранение конфигурации обратного входа в стороне от пути classpath теста также означает другие тесты, которые не волнует логирование не подбирает конфиг.

Тем не менее, это кажется "странным", я никогда не видел, чтобы кто-то использовал весенние тесты таким образом (для тестирования одного компонента без зависимостей и прямой зависимости от контекста). Тест начал свою жизнь как плановый тест POJO без заботы о весне, и он кажется более «чистым», чем и остается таким.

Есть ли передовая практика, применяемая при попытке проверить выходные данные объекта через SLF4J?

1 Ответ

0 голосов
/ 27 июня 2018

Ваш подход заключается в тестировании ваших текущих журналов конфигурации регистрации, а не того, что отправляется в систему регистрации.

Вместо правила OutputCapture вы можете перехватить запись в лог , написав свой собственный appender или высмеивая реализацию SLF4J. Вы даже можете провалить тест из своего пользовательского приложения, если в журнале будет записано что-то неправильное, , например ошибка . Я бы порекомендовал создать свое собственное @Rule, которое добавит вашего собственного тестового приложения, которое затем может выполнять любую пользовательскую логику для проверки совпадений или обеспечения регистрации правильных данных.

...