Java:测试系统输出,包括带有assertEquals的“新行”

时间:2017-01-16 10:36:38

标签: java unit-testing junit

我目前正在为战略设计模式编写单元测试。我正在将系统输出与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

修改

最快的解决方案似乎是在我的“\ n”前添加“\ 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());

另外:我忘了提到大部分代码来自Eric Freeman,Elisabeth Robson,Bert Bates和Kathy Sierra的书“Head First Design Patterns”。

4 个答案:

答案 0 :(得分: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构建预期的字符串。

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

如果测试失败,您可以提供更好的问题描述。 E.g。

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 :(得分:2)

到目前为止所有其他答案在技术上是正确的;但他们仍然没有提到一个核心问题:捕获 stdout / stderr然后进行精确的字符串匹配只是不好的做法; 假设您的班级写在那里。

当您测试多个方法调用时,甚至更多,并期望某些 final 输出“证明”所有方法都被调用,依此类推。

所以,是的,从理论上讲,你可以这样做(为了培训/学习目的);但你在这里使用的“模式”只是简单地说是“坏习惯”。当您稍后决定删除这些打印语句时会发生什么(因为,生产代码不执行打印语句)。然后你所有的测试都变得毫无价值。或者当其他一些用户将字符串中的一个字符更改为stdout时?

因此:真正的答案是退后一步,考虑这些方法调用会导致的真正“副作用”是什么;并寻找更好的方法来验证它们。

答案 2 :(得分: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());

答案 3 :(得分:1)

可能是,您使用的是Windows系统,需要检查\r\n而非\n