2017-01-16 94 views
5

我目前正在爲策略設計模式編寫單元測試。我將系統輸出與assertEquals方法中的一個字符串進行比較。輸出看起來相同,但我的測試仍然失敗。我在想我忘記了一些新的行或標籤?Java:測試包括「新行」與assertEquals系統輸出

我的單元測試:

import static org.junit.Assert.*; 

import java.io.ByteArrayOutputStream; 
import java.io.PrintStream; 

import org.junit.After; 
import org.junit.Before; 
import org.junit.Test; 

public class MiniDuck1Test { 

    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 cleanUpStreams() { 
     System.setOut(null); 
     System.setErr(null); 
    } 

    @Test 
    public void testDuck1() {  
     Duck mallard = new MallardDuck(); 
     mallard.performQuack(); 
     mallard.performFly(); 

     Duck model = new ModelDuck(); 
     model.performFly(); 
     model.setFlyBehavior(new FlyRocketPowered()); 
     model.performFly(); 

     assertEquals("Quack\nI'm flying!!\nI can't fly\nI'm flying with a rocket", outContent.toString().trim()); 
    } 
} 

輸出(第二和第三線出現紅):

Quack 
I'm flying!! 
I can't fly 
I'm flying with a rocket 

編輯:

最快的解決辦法似乎是增加一個「\ r「在我的」\ n「前面。多個答案告訴我這需要在Windows上完成。應用在這之後我的assertEquals樣子:

assertEquals("Quack\r\nI'm flying!!\r\nI can't fly\r\nI'm flying with a rocket", outContent.toString().trim()); 

另外:我忘了提,大部分代碼都來自書:「Head First設計模式」,由埃裏克·弗里曼,伊麗莎白·羅布森,伯特·貝茨和凱西塞拉利昂。

+1

而不是'Assert.equals()','TestCase.equals()'在顯示不匹配字符串的錯誤位置做了很好的工作。只需相應地編輯您的進口報表。 –

+1

嘗試比較字符串的長度。有些人認爲這可能是'\ r \ n',或者是其他一些無形的差異。 – shmosel

回答

2

除了其他的答案,如果你正在尋找一個獨立於平臺的方式.. 。

快速獨立於平臺的解決方案可以是取代的行分隔

String expected = "Quack\nI'm flying!!\nI can't fly\nI'm flying with a rocket" 
         .replaceAll("\\n|\\r\\n", System.getProperty("line.separator")); 
assertEquals(expected, outContent.toString().trim()); 

或使用PrintWriter噸o構建預期的字符串。

StringWriter expectedStringWriter = new StringWriter(); 
PrintWriter printWriter = new PrintWriter(expectedStringWriter); 

printWriter.println("Quack"); 
printWriter.println("I'm flying!!"); 
printWriter.println("I can't fly"); 
printWriter.println("I'm flying with a rocket"); 
printWriter.close(); 

String expected = expectedStringWriter.toString(); 
assertEquals(expected, outContent.toString()); 

或創建自己的斷言類重新使用它

class MyAssert { 

    public static void assertLinesEqual(String expectedString, String actualString){ 
     BufferedReader expectedLinesReader = new BufferedReader(new StringReader(expectedString)); 
     BufferedReader actualLinesReader = new BufferedReader(new StringReader(actualString)); 

     try { 
      int lineNumber = 0; 

      String actualLine; 
      while((actualLine = actualLinesReader.readLine()) != null){ 
       String expectedLine = expectedLinesReader.readLine(); 
       Assert.assertEquals("Line " + lineNumber, expectedLine, actualLine); 
       lineNumber++; 
      } 

      if(expectedLinesReader.readLine() != null){ 
       Assert.fail("Actual string does not contain all expected lines"); 
      } 
     } catch (IOException e) { 
      Assert.fail(e.getMessage()); 
     } finally { 
      try { 
       expectedLinesReader.close(); 
      } catch (IOException e) { 
       Assert.fail(e.getMessage()); 
      } 
      try { 
       actualLinesReader.close(); 
      } catch (IOException e) { 
       Assert.fail(e.getMessage()); 
      } 
     } 
    } 
} 

然後你就可以在測試失敗給出一個很好的解決問題的說明。例如。

MyAssert.assertLinesEqual(
     "Quack\nI'm flying!!\nI can not fly\nI'm flying with a rocket\n", 
     outContent.toString()); 

將輸出

org.junit.ComparisonFailure: Line 2 
Expected :I can not fly 
Actual :I can't fly 
1

嘗試使用\ r \ n而不是\ n。

assertEquals("Quack\r\nI'm flying!!\r\nI can't fly\r\nI'm flying with a rocket", outContent.toString().trim()); 
1

莫非,你是在Windows系統中,需要檢查\r\n,而不是僅僅\n

+1

我使用Eclipse在Windows 10,解決它 –

2

到目前爲止所有其他答案是技術上是正確的;但他們仍然沒有提到一個核心的事情:捕獲 stdout/stderr然後做精確的字符串匹配, 假設您的班級在那裏寫

更當你正在測試多個方法調用,並期待着某些最後輸出「證明」,所有的方法被稱爲,等等。

所以,是的,理論上你可以做的事情這樣(培訓/學習目的);但是你在這裏使用的「模式」只是被稱爲「不好的做法」。當您稍後決定刪除這些打印語句時會發生什麼(因爲生產代碼不會執行打印語句)。然後你所有的測試都變得毫無價值。或者當其他用戶更改字符串中的一個字符到stdout?

這樣:真正的答案是退後一步,考慮真正的「副作用」可能是什麼,這些方法調用會造成;並尋找更好的方法來驗證它們。

+0

什麼,如果你想測試的輸出,因爲你是深化發展在命令行上運行的應用程序? – Lezard

+0

簡單:那麼你有一個**創建**消息的組件。你測試。然後你有一個組件負責接收消息並將它們寫入某個地方,例如stdout。你測試。再次 - 無需通過從stdout讀取來測試消息的*佈局*!認爲「關注點隔離」和「單一責任原則」! – GhostCat

+0

這是好的單元測試,但你怎麼做一個集成測試,證明以下情形: - 打印輸出緩衝區一些文字,說10日線 - 打印一些轉義符,如「招行上」 +「明系列「4次 - 打印等3條線路 你怎麼斷言,最終輸出包含9分最後幾行文本(10 + - 4 + 3)? – Lezard