2017-01-16 107 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