簡體   English   中英

如何保存輸出Log4j在JUnit測試中發送到STDOUT?

[英]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));
    }
}

免責聲明

  • 我開發了這個庫,因為我找不到適合自己需要的解決方案。
  • 目前只提供log4jlog4j2logback綁定,但我很樂意添加更多內容。

嘗試在PrintStream上啟用autoflushing true:

PrintStream ps = new PrintStream(baos,true);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM