Java 如何使log4j error()调用在jUnit测试中引发异常?

Java 如何使log4j error()调用在jUnit测试中引发异常?,java,junit,log4j,Java,Junit,Log4j,我有一个Java项目正在使用JUnit(JUnit3和JUnit4风格的混合)进行测试,其中被测试的类可能会记录一个log4j错误。如果记录了这样的错误,我想让单元测试失败 是否有一种通用的方法来配置log4j或单元测试基础结构,以便在测试代码中调用log4j error()方法,从而引发运行时异常,从而使测试失败?AOP可能是一种方式,但我对其他可能性也感兴趣 这里的目的是清除代码中错误使用log4j error()的地方。也就是说,当记录了一个错误但没有发生异常或错误处理时,或者它不是真正的

我有一个Java项目正在使用JUnit(JUnit3和JUnit4风格的混合)进行测试,其中被测试的类可能会记录一个log4j错误。如果记录了这样的错误,我想让单元测试失败

是否有一种通用的方法来配置log4j或单元测试基础结构,以便在测试代码中调用log4j error()方法,从而引发运行时异常,从而使测试失败?AOP可能是一种方式,但我对其他可能性也感兴趣

这里的目的是清除代码中错误使用log4j error()的地方。也就是说,当记录了一个错误但没有发生异常或错误处理时,或者它不是真正的错误,或者它是并且应该被引发

例如:

更新:这就是我目前使用的解决方案。它基于sbridges的答案(添加到测试类):

然后在设置中:

Logger.getRootLogger().addAppender(crashAndBurnAppender);
和拆卸:

Logger.getRootLogger().removeAppender(crashAndBurnAppender);
您可以创建一个在错误级别登录时抛出AssertionError的新日志

大概

class TestAppender extends AppenderSkeleton {
    public void doAppend(LoggingEvent event) {
         if(event.getLevel() == Level.Error) {
              throw new AssertionError("logged at error:" + event.getMessage());
         }
    }
}
在你的测试中

Logger.getRootLogger().addAppender(new TestAppender());
编辑:正如Ralph指出的,在完成测试后移除TestAppender。

Log4j2解决方案 我只是偶然发现了这一点,但由于我使用的是Log4j的版本2,所以我不得不修改代码。我花了很长时间,因为大多数资源都是关于一堆混乱的配置工厂、配置程序、记录器上下文等等。我所做的可能不是最干净或官方的方式,但很简单

使用两个公共静态方法定义此类实用程序类:

private static Appender appender;

private static void enableThrowOnLog(Level level) {
    // Downcast: log4j.Logger -> log4j.core.Logger
    Logger rootLogger = (Logger) LogManager.getRootLogger();

    appender = new ThrowingAppender(level);
    appender.start();
    rootLogger.addAppender(appender);
}

public static void disableThrowOnLog() {
    // Downcast: log4j.Logger -> log4j.core.Logger
    Logger rootLogger = (Logger) LogManager.getRootLogger();

    appender.stop();
    rootLogger.removeAppender(appender);
    appender = null;
}

private static class ThrowingAppender extends AbstractAppender {
    private final Level level;

    public ThrowingAppender(Level level) {
        // Last parameter: ignoreExceptions -- must be false or exceptions will be swallowed
        super("ThrowingAppender", new AbstractFilter() {}, PatternLayout.createDefaultLayout(), false);
        this.level = level;
    }

    @Override
    public synchronized void append(LogEvent event) {
        Level eventLevel = event.getLevel();
        if (eventLevel.isMoreSpecificThan(this.level)) {
            String message = event.getMessage().getFormattedMessage();
            throw new AppenderLoggingException(eventLevel + " level was logged:\n> " + message);
        }
    }
}

理想情况下,在JUnit 4
@BeforeClass
方法中调用
enableThrowOnLog()
,在
@AfterClass
方法中调用
disableThrowOnLog()
,以便正确撤消对全局日志系统的更改。

您需要撤消
Logger.getRootLogger().addAppender(NewTestAppender())测试后!因为记录器是静态的,所以如果未删除此附加器,它也将在下一次测试中显示您必须在
@After
方法或finally语句中执行此操作,因为测试中的“正常”代码不会在异常之后执行。
Logger.getRootLogger().addAppender(new TestAppender());
private static Appender appender;

private static void enableThrowOnLog(Level level) {
    // Downcast: log4j.Logger -> log4j.core.Logger
    Logger rootLogger = (Logger) LogManager.getRootLogger();

    appender = new ThrowingAppender(level);
    appender.start();
    rootLogger.addAppender(appender);
}

public static void disableThrowOnLog() {
    // Downcast: log4j.Logger -> log4j.core.Logger
    Logger rootLogger = (Logger) LogManager.getRootLogger();

    appender.stop();
    rootLogger.removeAppender(appender);
    appender = null;
}

private static class ThrowingAppender extends AbstractAppender {
    private final Level level;

    public ThrowingAppender(Level level) {
        // Last parameter: ignoreExceptions -- must be false or exceptions will be swallowed
        super("ThrowingAppender", new AbstractFilter() {}, PatternLayout.createDefaultLayout(), false);
        this.level = level;
    }

    @Override
    public synchronized void append(LogEvent event) {
        Level eventLevel = event.getLevel();
        if (eventLevel.isMoreSpecificThan(this.level)) {
            String message = event.getMessage().getFormattedMessage();
            throw new AppenderLoggingException(eventLevel + " level was logged:\n> " + message);
        }
    }
}