Тестирование сообщений журнала, созданных Slf4j, без использования Log4J

Я хочу проверить метод, создает ли он правильные журналы или нет. Мой класс выглядит так:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;

class EventLogHandler {
    private final Logger logger = LoggerFactory.getLogger(EventLogHandler.class);
    private final Marker eventMarker = MarkerFactory.getMarker("EVENT");

    public void handle(final Event event) {
        final String log = SomeOtherClass.createLog(event);
        logger.info(eventMarker, log);
    }
}

Я видел несколько примеров/решений для тестирования журналов, но все они используют Log4j, который мы не используем в проекте. Я могу использовать только Log4j2 из spring-boot, Slf4j и Logback classic. Как я могу протестировать этот метод handle(...) с моими существующими зависимостями?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
0
1 569
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

С текущей реализацией вы не можете протестировать/проверить вызовы на logger, не задействовав систему ведения журнала и не подтверждая ее вывод, например. ввести logback и настроить его с помощью приложения stdout, а также захватить stdout и утвердить против него и т. д.

Чтобы протестировать свой класс, не делая ничего из этого, вам нужно заполучить экземпляр logger, который используется в EventLogHandler. Текущая реализация усложняет это, создавая logger следующим образом:

private final Logger logger = LoggerFactory.getLogger(EventLogHandler.class);

Обычный подход к тестированию в этом сценарии заключается в рефакторинге создания логгера таким образом, чтобы вы могли внедрить фиктивный экземпляр в EventLogHandler при выполнении тестов. Например:

class EventLogHandler {
    private final Marker eventMarker = MarkerFactory.getMarker("EVENT");
    private final Logger logger;

    public EventLogHandler() {
        this(LoggerFactory.getLogger(EventLogHandler.class));
    }

    // probably only used by your test case
    public EventLogHandler(Logger logger) {
        this.logger = logger;
    }

    public void handle(final Event event) {
        logger.info(eventMarker, log);
    }
}

Затем проверьте это так:

@Test
public void someTest() {
    Logger logger = Mockito.mock(Logger.class);
    EventLogHandler sut = new EventLogHandler(logger);

    sut.handle(event);

    // verify that the right state is extracted from the given event and that the correct marker is used
    Mockito.verify(logger).info(..., ...);
}

Менее распространенной альтернативой было бы использование Powermock, чтобы позволить вам имитировать этот вызов: LoggerFactory.getLogger(EventLogHandler.class);, а затем использовать Mockito для проверки вызовов на него так же, как показано выше.

Является ли хорошим подходом изменить Logger на неокончательный (потому что мне все еще нужно сохранить LoggerFactory.getLogger()) и добавить конструктор только для проверки метода?

Melih 16.04.2019 10:50

Logger по-прежнему окончательный, так как он всегда устанавливается через конструктор. Ответ на другую часть вашего вопроса - «добавление конструктора только для проверки метода» - таков: это зависит от того, это правильный подход к тестированию. Это способ разработки класса таким образом, чтобы он был проверяемый. Если вы не хотите этого делать, вы можете рассмотреть другой подход с использованием Powermock для имитации конструкции Logger внутри EventLogHandler.

glytching 16.04.2019 11:00

Извините, я не видел конструктор по умолчанию, так что он окончательный, вы правы. Что касается другого вопроса, я забыл добавить, откуда берется параметр журнала, он исходил из objectMapper в виде строки. Поскольку эта логика была приватной в EventLogHandler, я не смог проверить вывод. Вместо этого я перенес эту логику в другой класс, чтобы ее можно было протестировать.

Melih 16.04.2019 17:25

Другие вопросы по теме