2009-07-13 119 views
265

我需要爲設計不佳的舊應用程序編寫JUnit測試,並將大量錯誤消息寫入標準輸出。當getResponse(String request)方法正確的行爲是返回XML響應:對於System.out.println()的JUnit測試()

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

相關,但不是http://stackoverflow.com/questions/3381801/how-do-i-unit-test-saving-file-to-the-disk – Raedwald 2014-07-05 13:22:29

回答

445

使用ByteArrayOutputStream和System.setXXX很簡單:

private final ByteArrayOutputStream outContent = new ByteArrayOutputStream(); 
private final ByteArrayOutputStream errContent = new ByteArrayOutputStream(); 

@Before 
public void setUpStreams() { 
    System.setOut(new PrintStream(outContent)); 
    System.setErr(new PrintStream(errContent)); 
} 

@After 
public void restoreStreams() { 
    System.setOut(System.out); 
    System.setErr(System.err); 
} 

樣品測試情況:

@Test 
public void out() { 
    System.out.print("hello"); 
    assertEquals("hello", outContent.toString()); 
} 

@Test 
public void err() { 
    System.err.print("hello again"); 
    assertEquals("hello again", errContent.toString()); 
} 

我用這個代碼來測試命令行選項(斷言-version輸出版本字符串,等等等等)

編輯: 此答案的前幾個版本在測試後稱爲System.setOut(null);這是NullPointerExceptions評論者引用的原因。

+0

此外,我已經使用JUnitMatchers來測試響應: assertThat(result,containsString(「 2009-07-13 14:08:27

+3

我更喜歡使用System.setOut(null)將流恢復到VM啓動時的狀態 – tddmonkey 2009-07-13 14:13:19

+5

javadoc沒有說能夠將null傳遞給System.setOut或System.setErr。你確定這將適用於所有的JRE嗎? – finnw 2009-08-20 15:29:31

19

您可以通過setOut()設置的System.out打印流(和inerr)。你可以重定向到一個打印流,記錄到一個字符串,然後檢查?這似乎是最簡單的機制。

(!我會主張,在某個階段,應用程序轉換爲一些日誌框架 - 但我懷疑你已經意識到這一點)

+1

重複。那是什麼來在我看來,但我不相信沒有標準的JUnit方式來做到這一點。謝謝,大腦。但信貸得到了dfa的實際努力。 – 2009-07-13 14:07:04

7

@dfa答案很棒,所以我更進一步,讓它能夠測試輸出塊。

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

來源爲TestHelper:該TestHelper和CaptureTest在同一個文件中定義

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; 
} 

注意。

然後在您的測試中,您可以導入靜態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()); 
      } 
     }); 
} 
2

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

79

我知道這是一個古老的線程,但有一個很好的圖書館要做到這一點:

System Rules

來自實例文檔:

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)以及命令行工具需要測試的其他內容。

15

不是重定向System.out的,我會重構,通過傳遞PrintStream作爲一個合作者,然後在生產中使用System.out試諜在測試使用System.out.println()類。

生產中

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

在Test

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

討論

這樣被測類成爲通過簡單的重構可測試,而無需需要間接標準輸出的重定向或系統規則的隱蔽攔截。

10

稍微偏離主題,但在情況下,一些人(像我一樣,當我第一次發現這個線程)可能有興趣在捕獲由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,log4j2logback的綁定,但我很樂意添加更多。
1

不能使用的System.out.println或使用記錄器API同時使用的JUnit直接打印。但是,如果你想查詢的任何值,那麼你根本無法使用

Assert.assertEquals("value", str); 

它會拋出以下斷言錯誤:

java.lang.AssertionError: expected [21.92] but found [value] 

你的價值應該是21.92,現在,如果你將測試使用像低於此值你的測試用例會通過。

Assert.assertEquals(21.92, str); 
5

如果你使用Spring啓動(你提到你與一箇舊的應用程序工作,所以你可能不是,但它可能是用別人的),那麼你可以使用org.springframework .boot.test.rule.OutputCapture以下列方式:

@Rule 
public OutputCapture outputCapture = new OutputCapture(); 

@Test 
public void out() { 
    System.out.print("hello"); 
    assertEquals(outputCapture.toString(), "hello"); 
} 
0

爲出

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

爲ERR

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