如何对记录器中的消息执行 JUnit 断言

新手上路,请多包涵

我有一些被测代码调用 Java 记录器来报告其状态。在 JUnit 测试代码中,我想验证是否在此记录器中创建了正确的日志条目。大致如下:

 methodUnderTest(bool x){
    if(x)
        logger.info("x happened")
}

@Test tester(){
    // perhaps setup a logger first.
    methodUnderTest(true);
    assertXXXXXX(loggedLevel(),Level.INFO);
}

我想这可以用一个特别适应的记录器(或处理程序,或格式化程序)来完成,但我更愿意重新使用已经存在的解决方案。 (老实说,我不清楚如何从记录器获取 logRecord,但假设这是可能的。)

原文由 Jon 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 998
2 个回答

非常感谢这些(令人惊讶的)快速而有用的答案;他们让我走上了解决问题的正确道路。

代码库是我想使用它,使用 java.util.logging 作为它的记录器机制,而且我对这些代码感觉不够熟悉,无法将其完全更改为 log4j 或记录器接口/外观。但基于这些建议,我“破解”了一个 julhandler 扩展,这是一种享受。

下面是一个简短的总结。扩展 java.util.logging.Handler

 class LogHandler extends Handler
{
    Level lastLevel = Level.FINEST;

    public Level  checkLevel() {
        return lastLevel;
    }

    public void publish(LogRecord record) {
        lastLevel = record.getLevel();
    }

    public void close(){}
    public void flush(){}
}

显然,您可以从 LogRecord 存储尽可能多的内容,或者将它们全部推入堆栈直到溢出。

在准备 junit-test 时,您创建一个 java.util.logging.Logger 并添加这样一个新的 LogHandler 到它:

 @Test tester() {
    Logger logger = Logger.getLogger("my junit-test logger");
    LogHandler handler = new LogHandler();
    handler.setLevel(Level.ALL);
    logger.setUseParentHandlers(false);
    logger.addHandler(handler);
    logger.setLevel(Level.ALL);

setUseParentHandlers() 的调用是为了使正常处理程序静音,以便(对于此 junit-test 运行)不会发生不必要的日志记录。做任何你的被测代码需要使用这个记录器,运行测试和 assertEquality:

     libraryUnderTest.setLogger(logger);
    methodUnderTest(true);  // see original question.
    assertEquals("Log level as expected?", Level.INFO, handler.checkLevel() );
}

(当然,您可以将大部分工作转移到 @Before 方法中并进行其他各种改进,但这会使演示文稿变得混乱。)

原文由 Jon 发布,翻译遵循 CC BY-SA 2.5 许可协议

我也需要这个几次。我在下面整理了一个小样本,您可以根据自己的需要进行调整。基本上,您创建自己的 Appender 并将其添加到您想要的记录器中。如果您想收集所有内容,根记录器是一个很好的起点,但如果您愿意,可以使用更具体的记录器。完成后不要忘记删除 Appender,否则可能会造成内存泄漏。 Below I’ve done it within the test, but setUp or @Before and tearDown or @After might be better places, depending on your需要。

此外,下面的实现将所有内容收集在内存中的 List 中。如果你记录了很多你可能会考虑添加一个过滤器来删除无聊的条目,或者将日志写入磁盘上的临时文件(提示: LoggingEventSerializable ,所以你如果您的日志消息是,应该能够只序列化事件对象。)

 import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.spi.LoggingEvent;
import org.junit.Test;

import java.util.ArrayList;
import java.util.List;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

public class MyTest {
    @Test
    public void test() {
        final TestAppender appender = new TestAppender();
        final Logger logger = Logger.getRootLogger();
        logger.addAppender(appender);
        try {
            Logger.getLogger(MyTest.class).info("Test");
        }
        finally {
            logger.removeAppender(appender);
        }

        final List<LoggingEvent> log = appender.getLog();
        final LoggingEvent firstLogEntry = log.get(0);
        assertThat(firstLogEntry.getLevel(), is(Level.INFO));
        assertThat((String) firstLogEntry.getMessage(), is("Test"));
        assertThat(firstLogEntry.getLoggerName(), is("MyTest"));
    }
}

class TestAppender extends AppenderSkeleton {
    private final List<LoggingEvent> log = new ArrayList<LoggingEvent>();

    @Override
    public boolean requiresLayout() {
        return false;
    }

    @Override
    protected void append(final LoggingEvent loggingEvent) {
        log.add(loggingEvent);
    }

    @Override
    public void close() {
    }

    public List<LoggingEvent> getLog() {
        return new ArrayList<LoggingEvent>(log);
    }
}

原文由 Ronald Blaschke 发布,翻译遵循 CC BY-SA 2.5 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题