[java] System.out.println()的JUnit測試


Answers

我知道這是一個舊線程,但有一個很好的庫來做到這一點:

系統規則

來自文檔的示例:

public void MyTest {
    @Rule
    public final SystemOutRule systemOutRule = new SystemOutRule().enableLog();

    @Test
    public void overrideProperty() {
        System.out.print("hello world");
        assertEquals("hello world", systemOutRule.getLog());
    }
}

它還將允許您捕獲System.exit(-1)以及命令行工具需要測試的其他內容。

Question

我需要為一個設計不好的舊應用程序編寫JUnit測試,並且會向標準輸出寫入大量錯誤消息。 當getResponse(String request)方法行為正確時,它返回一個XML響應:

@BeforeClass
public static void setUpClass() throws Exception {
    Properties queries = loadPropertiesFile("requests.properties");
    Properties responses = loadPropertiesFile("responses.properties");
    instance = new ResponseGenerator(queries, responses);
}

@Test
public void testGetResponse() {
    String request = "<some>request</some>";
    String expResult = "<some>response</some>";
    String result = instance.getResponse(request);
    assertEquals(expResult, result);
}

但是當它變得格式不正確的XML或不理解請求時,它將返回null並將一些內容寫入標準輸出。

有沒有辦法在JUnit中聲明控制台輸出? 要捕捉如下情況:

System.out.println("match found: " + strExpr);
System.out.println("xml not well formed: " + e.getMessage());



您不想重定向system.out流,因為它重定向了整個JVM。 在JVM上運行的任何其他內容都可能會變得混亂。 有更好的方法來測試輸入/輸出。 看看存根/嘲笑。




出去

@Test
void it_prints_out() {

    PrintStream save_out=System.out;final ByteArrayOutputStream out = new ByteArrayOutputStream();System.setOut(new PrintStream(out));

    System.out.println("Hello World!");
    assertEquals("Hello World!\r\n", out.toString());

    System.setOut(save_out);
}

因為錯誤

@Test
void it_prints_err() {

    PrintStream save_err=System.err;final ByteArrayOutputStream err= new ByteArrayOutputStream();System.setErr(new PrintStream(err));

    System.err.println("Hello World!");
    assertEquals("Hello World!\r\n", err.toString());

    System.setErr(save_err);
}



@dfa的回答非常好,所以我更進一步,以便測試輸出塊。

首先,我使用TestHelper方法創建了TestHelper ,該方法接受惱人的類CaptureTest 。 captureOutput方法執行設置和拆除輸出流的工作。 當調用CaptureOutputtest方法的實現時,它可以訪問測試塊的輸出生成。

TestHelper的源代碼:

public class TestHelper {

    public static void captureOutput( CaptureTest test ) throws Exception {
        ByteArrayOutputStream outContent = new ByteArrayOutputStream();
        ByteArrayOutputStream errContent = new ByteArrayOutputStream();

        System.setOut(new PrintStream(outContent));
        System.setErr(new PrintStream(errContent));

        test.test( outContent, errContent );

        System.setOut(new PrintStream(new FileOutputStream(FileDescriptor.out)));
        System.setErr(new PrintStream(new FileOutputStream(FileDescriptor.out)));

    }
}

abstract class CaptureTest {
    public abstract void test( ByteArrayOutputStream outContent, ByteArrayOutputStream errContent ) throws Exception;
}

請注意,TestHelper和CaptureTest是在同一個文件中定義的。

然後在您的測試中,您可以導入靜態captureOutput。 這裡是一個使用JUnit的例子:

// imports for junit
import static package.to.TestHelper.*;

public class SimpleTest {

    @Test
    public void testOutput() throws Exception {

        captureOutput( new CaptureTest() {
            @Override
            public void test(ByteArrayOutputStream outContent, ByteArrayOutputStream errContent) throws Exception {

                // code that writes to System.out

                assertEquals( "the expected output\n", outContent.toString() );
            }
        });
}



我沒有重定向System.out ,而是通過傳遞PrintStream作為協作者,然後在生產環境中使用System.out測試中使用Test Spy來重構使用System.out.println()的類。

在生產中

ConsoleWriter writer = new ConsoleWriter(System.out));

在測試中

ByteArrayOutputStream outSpy = new ByteArrayOutputStream();
ConsoleWriter writer = new ConsoleWriter(new PrintStream(outSpy));
writer.printSomething();
assertThat(outSpy.toString(), is("expected output"));

討論

通過這種方式,被測試的類可以通過簡單的重構進行測試,而不需要間接重定向標準輸出或使用系統規則模糊攔截。




Related