如何使log4j error()调用在jUnit测试中抛出异常



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

是否有一种通用的方法来配置log4j或单元测试基础架构,以便在测试代码中对log4j error()方法进行任何调用,抛出运行时异常,因此测试失败?AOP可能是一种方法,但是我对其他的可能性也很感兴趣。

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

,

public class MyTest extends TestCase {
    public void testLogAnError() {
        // Want to make this fail
        new MyClass().logAnError();
    }
}
public class MyClass() {
    static Logger logger = Logger.getLogger("foo");
    public void logAnError() {
        // I'm logging an error, but not doing anything about it
        logger.error("Something bad, or is it?");
        // TODO throw an exception or don't log an error if there isn't one
    }
}

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

private static final Appender crashAndBurnAppender = new NullAppender () {
    public void doAppend(LoggingEvent event) {
         if(event.getLevel() == Level.ERROR) {
              throw new AssertionError("logged at error:" + event.getMessage());
         }
    }
};

然后在setUp中:

Logger.getRootLogger().addAppender(crashAndBurnAppender);

和拆卸:

Logger.getRootLogger().removeAppender(crashAndBurnAppender);

你可以创建一个新的Appender,当你记录到错误级别时抛出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(),这样对全局日志系统的更改就可以正确地撤消。

最新更新