[英]How to save output Log4j sends to STDOUT in a JUnit test?
我正在编写测试,我想通过测试方法捕获STDOUT上发送的消息。 这是我的代码:
@Test
public void testAction() throws IllegalArgumentException, NoSuchMethodException, IllegalAccessException, InvocationTargetException,
CmdLineException, IOException {
PrintStream originalSTDOUT = System.out;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(baos);
try {
System.setOut(ps);
// Call to the method that will print text to STDOUT...
ps.flush();
String batchLog = baos.toString("UTF-8");
assertTrue("Invalid exception text !", batchLog.contains("my expected text..."));
} finally {
System.setOut(originalSTDOUT);//Restore original STDOUT
originalSTDOUT.write(baos.toByteArray());// Write back to STDOUT, even if I comment this line, outputs go to STDOUT...
ps.close();
}
}
不幸的是,虽然我仍然可以将预期的文本读取到STDOUT,但batchLog
始终为空。
将文本打印到STDOUT的方法实际上会捕获异常。 然后它将它传递给Logger
如下所示:
log.warn(“发生错误:”,e);
其中e
是我在测试中调用的方法中引发的异常。
Logger
使用此appender打印其消息: org.apache.log4j.ConsoleAppender
。 没有特殊配置应用于此appender。
我错过了什么?
PS:这个SO答案很有意思,但它对我不起作用,因为在StandardOutputStreamLog规则可以行动之前已经创建了ConsoleAppender
。
Java 6
Junit 4.10
我终于解决了我的问题!
我的第一次尝试是错误的,因为@Joni在他的评论中指出,我将STDOUT重定向太晚了: ConsoleAppender
已经创建了。
由于异常消息由Logger
处理,因此我决定将StringWriter
支持的WriterAppender
添加到它以获取消息。
这是我的工作解决方案:
@Test
public void testAction() throws IllegalArgumentException, NoSuchMethodException, IllegalAccessException, InvocationTargetException,
CmdLineException, IOException {
// Setup WriterAppender
Writer w = new StringWriter();
Layout l = new PatternLayout("%m%n");
WriterAppender wa = new WriterAppender(l, w);
wa.setEncoding("UTF-8");
wa.setThreshold(Level.ALL);
wa.activateOptions();// WriterAppender does nothing here, but I like defensive code...
// Add it to logger
Logger log = Logger.getLogger(ExceptionHandler.class);// ExceptionHandler is the class that contains this code : `log.warn("An error has occured:", e);'
log.addAppender(wa);
try {
// Call to the method that will print text to STDOUT...
String batchLog = w.toString();
assertTrue("Invalid exception text !", batchLog.contains("my expected text..."));
} finally {
// Cleanup everything...
log.removeAppender(wa);
wa.close();
}
}
稍微偏离主题,但是如果有些人(像我这样,当我第一次找到这个帖子时)可能对通过SLF4J捕获日志输出感兴趣,那么commons-testing的JUnit @Rule
可能会有所帮助:
public class FooTest {
@Rule
public final ExpectedLogs logs = new ExpectedLogs() {{
captureFor(Foo.class, LogLevel.WARN);
}};
@Test
public void barShouldLogWarning() {
assertThat(logs.isEmpty(), is(true)); // Nothing captured yet.
// Logic using the class you are capturing logs for:
Foo foo = new Foo();
assertThat(foo.bar(), is(not(nullValue())));
// Assert content of the captured logs:
assertThat(logs.isEmpty(), is(false));
assertThat(logs.contains("Your warning message here"), is(true));
}
}
免责声明 :
log4j
, log4j2
和logback
绑定,但我很乐意添加更多内容。 尝试在PrintStream上启用autoflushing true:
PrintStream ps = new PrintStream(baos,true);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.