Исключить исключение журнала для событий журнала ERROR - программирование

Исключить исключение журнала для событий журнала ERROR

При выполнении модульных тестов я хотел бы пропустить любые тесты, в течение которых регистрируется сообщение уровня ERROR. Каким будет самый простой способ добиться этого, используя SLF4J/Logback? Я хотел бы избежать написания собственной реализации ILoggerFactory.

Я попытался написать пользовательский Appender, но я не могу распространять исключения через код, вызывающий Appender, все исключения из Appender попадают туда.

4b9b3361

Ответ 1

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

Я размещаю свой код для этого ответа в общедоступном домене:

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.AppenderBase;
import org.junit.rules.ExternalResource;
import org.slf4j.LoggerFactory;
import static org.junit.Assert.fail;

/**
 * A JUnit {@link org.junit.Rule} which attaches itself to Logback, and fails the test if an error is logged.
 * Designed for use in some tests, as if the system would log an error, that indicates that something
 * went wrong, even though the error was correctly caught and logged.
 */
public class FailOnErrorLogged extends ExternalResource {

    private FailOnErrorAppender appender;

    @Override
    protected void before() throws Throwable {
        super.before();
        final LoggerContext loggerContext = (LoggerContext)(LoggerFactory.getILoggerFactory());
        final Logger rootLogger = (Logger)(LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME));
        appender = new FailOnErrorAppender();
        appender.setContext(loggerContext);
        appender.start();
        rootLogger.addAppender(appender);
    }

    @Override
    protected void after() {
        appender.stop();
        final Logger rootLogger = (Logger)(LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME));
        rootLogger.detachAppender(appender);
        super.after();
    }

    private static class FailOnErrorAppender extends AppenderBase<ILoggingEvent> {
        @Override
        protected void append(final ILoggingEvent eventObject) {
            if (eventObject.getLevel().isGreaterOrEqual(Level.ERROR)) {
                fail("Error logged: " + eventObject.getFormattedMessage());
            }
        }
    }
}

Пример использования:

import org.junit.Rule;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ExampleTest {
    private static final Logger log = LoggerFactory.getLogger(ExampleTest.class);

    @Rule
    public FailOnErrorLogged failOnErrorLogged = new FailOnErrorLogged();

    @Test
    public void testError() {
        log.error("Test Error");
    }

    @Test
    public void testInfo() {
        log.info("Test Info");
    }
}

Метод testError завершается с ошибкой, и метод testInfo проходит. Он работает так же, если тест вызывает реальный класс-тест, который также регистрирует ошибку.

Ответ 2

Итак, вы хотите сбить свой тестовый пример, если вызывается сообщение об ошибке сообщения журнала.

  • Используйте инъекцию зависимостей, чтобы связать проверяемый код с используемым регистратором.
  • Внедрение тестового двойника, реализующего интерфейс регистратора SLF4J, и который ничего не делает для большинства методов, но генерирует AssertionError для методов регистрации ошибок.
  • В установочной части тестового примера введите двойной тест.

Ответ 3

Структуры ведения журнала обычно предназначены для того, чтобы не вызывать каких-либо исключений для пользователя. Другой вариант (в дополнение к ответу Радвальда) - создать пользовательский appender, который устанавливает для статического логического флага значение true, когда регистрируется сообщение ERROR, reset этот флаг в методе настройки и проверяет его в методе teardown (или создает правило JUnit для reset/отметьте флаг).