使Logback在ERROR级别的日志事件上抛出异常

问题描述 投票:0回答:3

运行单元测试时,我希望在记录错误级别消息的任何测试中失败。使用 SLF4J/Logback 实现此目的最简单的方法是什么?我想避免编写自己的 ILoggerFactory 实现。

我尝试编写一个自定义 Appender,但我无法通过调用 Appender 的代码传播异常,来自 Appender 的所有异常都会被捕获。

unit-testing slf4j logback
3个回答
6
投票

关键是编写一个自定义的appender。你没有说你使用哪个单元测试框架,但对于 JUnit,我需要做类似的事情(它比所有错误稍微复杂一点,但基本上是相同的概念),并创建一个 JUnit @Rule 添加我的附加程序,并且追加器根据需要未通过测试。

我将此答案的代码放在公共领域:

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 方法通过。如果测试调用也记录错误的真实被测类,它的工作原理是相同的。


1
投票

日志框架通常设计为不会向用户抛出任何异常。另一种选择(除了 Raedwald 的答案)是创建一个自定义附加程序,在记录错误消息时将静态布尔标志设置为 true,在设置方法中重置此标志并在拆卸方法中检查它(或创建一个 JUnit重置/检查标志的规则)。


0
投票

因此,如果调用记录器的任何错误报告消息,您希望测试用例失败。

  1. 使用依赖注入将要测试的代码与其应使用的记录器关联起来。
  2. 实现一个测试替身,该测试替身实现了 SLF4J 记录器接口,它对大多数方法不执行任何操作,但对错误记录方法抛出 AssertionError。
  3. 在测试用例的设置部分,注入测试替身。
© www.soinside.com 2019 - 2024. All rights reserved.