Я хочу проверить метод, создает ли он правильные журналы или нет. Мой класс выглядит так:
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(...) с моими существующими зависимостями?




С текущей реализацией вы не можете протестировать/проверить вызовы на 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 по-прежнему окончательный, так как он всегда устанавливается через конструктор. Ответ на другую часть вашего вопроса - «добавление конструктора только для проверки метода» - таков: это зависит от того, это правильный подход к тестированию. Это способ разработки класса таким образом, чтобы он был проверяемый. Если вы не хотите этого делать, вы можете рассмотреть другой подход с использованием Powermock для имитации конструкции Logger внутри EventLogHandler.
Извините, я не видел конструктор по умолчанию, так что он окончательный, вы правы. Что касается другого вопроса, я забыл добавить, откуда берется параметр журнала, он исходил из objectMapper в виде строки. Поскольку эта логика была приватной в EventLogHandler, я не смог проверить вывод. Вместо этого я перенес эту логику в другой класс, чтобы ее можно было протестировать.
Является ли хорошим подходом изменить Logger на неокончательный (потому что мне все еще нужно сохранить LoggerFactory.getLogger()) и добавить конструктор только для проверки метода?