How to verify (with unit test) that error stack is printed in the log file?
在继续回答此问题时,我编写了一个单元测试,以验证在发生错误的情况下,堆栈将被打印在日志文件中。
测试方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
单元测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | import ch.qos.logback.classic.Level; import ch.qos.logback.classic.Logger; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.read.ListAppender; import org.slf4j.LoggerFactory; @Test public void getFileQualifier() { // get Logback Logger Logger logger = (Logger) LoggerFactory.getLogger(QService.class); // create and start a ListAppender ListAppender<ILoggingEvent> listAppender = new ListAppender<>(); listAppender.start(); // add the appender to the logger // addAppender is outdated now logger.addAppender(listAppender); // call method under test QService.getFq(null); // JUnit assertions List<ILoggingEvent> logsList = listAppender.list; Assert.assertEquals("unable to calculate SomeThing. Error:", logsList.get(0) .getFormattedMessage()); Assert.assertEquals(Level.ERROR, logsList.get(0) .getLevel()); Assert.assertEquals("java.lang.NullPointerException: null", logsList.get(1) .getMessage()); Assert.assertEquals(Level.ERROR, logsList.get(1) .getLevel()); Assert.assertThat("(QService.java", containsString(logsList.get(2) .getMessage())); Assert.assertEquals(Level.ERROR, logsList.get(2) .getLevel()); } |
好吧,尽管我可以看到堆栈确实已打印在日志文件中,但是由于
java.lang.IndexOutOfBoundsException: Index 1 out of bounds for length 1
为什么会发生以及如何对其进行测试?
编辑
答案:
答案(都是@Gavin的答案和评论的引号,谢谢):
关于第一个问题(为什么会发生)的答案是:
It looks to me that exceptions is stored separately from the message in the log event
关于第二个问题(如何进行测试),答案是:
to find what you are looking for in the list of log events and can be expressed in a manner suitable to your domain, e.g checking the that a Throwable was logged, perhaps looking in org.apache.log4j.spi.LoggingEvent for appropriate methods
最后,我要验证的代码是:
1 | Assert.assertEquals(logsList.get(0).getThrowableProxy().getClassName(),"java.lang.NullPointerException"); |
这是我过去捕获日志消息的方式,这是基于一个似乎不再可用的旧博客(不是我写的)。
这是为Java 7/8和Junit4编写的相当老的代码。
我会尽量保持简短:)
首先,您需要一个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | public class RuleAppender extends AppenderSkeleton { private final List<LoggingEvent> loggingEvents = new ArrayList<>(); protected RuleAppender() { super(true); this.setThreshold(Level.TRACE); setName("Rule Appender"); } @Override public void close() { // No op in this case } @Override public boolean requiresLayout() { return false; } @Override protected void append(final LoggingEvent event) { loggingEvents.add(event); } public boolean hasEventsMeeting(LogExpectation logExpectation) { // Use the LogExpectation to determine if the list of log events contains what you want. } @Override public String toString() { return"RuleAppender"; } } |
然后将其包裹在Junit规则中,以使将Appender添加到Log4J变得更加容易,我通过实现
1 2 | LogManager.getRootLogger().addAppender(ruleAppender); LogManager.getRootLogger().setLevel(Level.ALL); |
注意:
只要在测试之前执行了以上两行,以确保将追加添加到Log4J(仍然需要自定义追加器),就可以在没有JUnit规则的情况下完成此操作。
我还没有进入JUnit规则代码,因为我们可能应该转到不支持Rules的JUnit 5,并且我也没有进入