【问题标题】:How to save output Log4j sends to STDOUT in a JUnit test?如何在 JUnit 测试中保存输出 Log4j 发送到 STDOUT?
【发布时间】:2013-08-12 11:18:50
【问题描述】:

我正在编写一个测试,我想捕获测试方法在 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();
    }
}

不幸的是,batchLog 始终为空,尽管我仍然可以将预期的文本读取到 STDOUT。

将文本打印到 STDOUT 的方法实际上捕获了一个异常。然后它将它传递给Logger,如下所示:

log.warn("发生错误:", e);

e 是我在测试中调用的方法中引发的异常。

Logger 使用此附加程序打印其消息:org.apache.log4j.ConsoleAppender。此附加程序没有应用特殊配置。

我错过了什么?

附: 这个SO answer 很有趣,但它对我不起作用,因为在StandardOutputStreamLog rule 可以行动之前已经创建了ConsoleAppender

Java 6
Junit 4.10

【问题讨论】:

  • 方法如何打印文本? System.setOut 只改变System.out 字段的值;它可能使用该字段的缓存值或使用其他方式写入标准输出。
  • 代码作为独立的主要方法工作正常。检查您的 JUnit 设置和拆卸方法。问题出在其他地方。
  • 不能用普通的 System.out.println(...) 重现这个,你如何将文本打印到标准输出?
  • @Joni 我已经更新了我的帖子,添加了该方法如何将文本打印到标准输出。
  • 既然您使用的是 Log4J,您就不能更改日志配置吗? ConsoleAppender 类使用创建 appender 时 System.out 的任何值;当您的测试执行时,更改它为时已晚。见源:docjar.com/html/api/org/apache/log4j/ConsoleAppender.java.html

标签: java redirect junit stdout junit4


【解决方案1】:

我终于解决了我的问题!

我的第一次尝试是错误的,因为我重定向 STDOUT 太晚了,正如@Joni 在他的 cmets 中所说:ConsoleAppender 已经创建。

由于异常消息由Logger 处理,因此我决定添加一个WriterAppender 以支持StringWriter 以获取消息。

这是我的工作解决方案:

@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();
        }
}

【讨论】:

    【解决方案2】:

    有点离题,但如果有些人(比如我,当我第一次发现这个线程时)可能对通过 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));
        }
    }
    

    免责声明

    • 我开发了这个库,因为我找不到任何适合我自己需求的解决方案。
    • 目前只有log4jlog4j2logback 的绑定可用,但我很乐意添加更多。

    【讨论】:

      【解决方案3】:

      尝试在 PrintStream 上启用 autoflushing true:

      PrintStream ps = new PrintStream(baos,true);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-05-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-08-03
        • 2021-11-09
        • 2015-07-21
        • 1970-01-01
        相关资源
        最近更新 更多