首页 文章

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

提问于
浏览
7

我有一个Java项目正在使用JUnit(Junit 3和4样式的混合)进行测试,其中被测试的类可能会记录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);

2 回答

  • 0

    您可以创建一个新的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());
    

    编辑:正如拉尔夫指出的那样,在完成测试后删除TestAppender .

  • 14

    Log4j2解决方案

    我偶然发现了这一点,但由于我使用的是Log4j的第2版,我不得不调整代码 . 我花了很长时间,因为大多数资源都是关于混乱的配置工厂,配置器, Logger 上下文等等 . 我所做的可能不是最干净或最正式的方式,但它很简单 .

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

    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() ,以便正确撤消对全局日志系统的更改 .

相关问题