如何模拟输出流?

2022-09-03 01:16:20

通过“输出蒸汽”,我的意思是任何接收字节序列,字符或其他任何东西的对象。所以,java.io.OutputStream,还有java.io.Writer,javax.xml.stream.XMLStreamWriter的writeCharacters方法,等等。

我正在为一个类编写基于模拟的测试,该类的主要功能是将数据流写入其中一个类(XMLStreamWriter,碰巧)。

问题在于,数据流是在对 write 方法的一系列调用中写入的,但重要的不是调用,而是数据。例如,给定一个 XMLStreamWriter ,这些:out

out.writeCharacters("Hello, ");
out.writeCharacters("world!");

等效于此:

out.writeCharacters("Hello, world!");

发生这种情况(就我而言)真的无关紧要。会有一些特定的调用序列,但我不在乎它是什么,所以我不想写那个特定序列的期望。我只想期望以任何一种方式写入某个数据流。

一种选择是切换到基于状态的测试。我可以在缓冲区中积累数据,并对此做出断言。但是因为我正在编写XML,这意味着要做出一些相当复杂和丑陋的断言。嘲笑似乎是处理编写 XML 这一更大问题的更好方法。

那么我该如何用模拟来做到这一点呢?

我正在使用Moxie进行模拟,但我有兴趣听到任何模拟库的方法。


答案 1

测试输出或输入流的一个相当优雅的策略是使用 PipedInputStreamPipedOutputStream 类。您可以在设置测试时将它们连接在一起,然后在执行目标方法后检查已写入的内容。

您可以在另一个方向上准备一些输入,然后让测试也从输入流中读取此准备好的数据。

在你的例子中,你可以用 PipedOutputStream 模拟那个“out”变量,然后用这种方式将 PipedInputStream 插入到它:

private BufferedReader reader;

@Before
public void init() throws IOException {
    PipedInputStream pipeInput = new PipedInputStream();
    reader = new BufferedReader(
            new InputStreamReader(pipeInput));
    BufferedOutputStream out = new BufferedOutputStream(
            new PipedOutputStream(pipeInput))));
    //Here you will have to mock the output somehow inside your 
    //target object.
    targetObject.setOutputStream (out);
    }


@Test
public test() {
    //Invoke the target method
    targetObject.targetMethod();

    //Check that the correct data has been written correctly in 
    //the output stream reading it from the plugged input stream
    Assert.assertEquals("something you expects", reader.readLine());
    }

答案 2

我承认,我可能偏向于使用ByteArrayOutputStream作为最低级别的ProstOff,在执行后获取数据并形成所需的任何断言。(也许使用SAX或其他XML解析器来读取数据并深入研究结构)

如果你想用一个模拟来做到这一点,我承认我有点偏爱Mockito,我认为你可以用一个自定义的答案来完成你想要做的事情当用户在你的模拟上调用写字符时,只需将他们的参数附加到缓冲区,然后你可以在之后对它进行断言。

这是我脑海中的内容(手写的,还没有执行,所以语法问题是预期的:))

public void myTest() {
    final XMLStreamWriter mockWriter = Mockito.mock(XMLStreamWriter.class);
    final StringBuffer buffer = new StringBuffer();
    Mockito.when(mockWriter.writeCharacters(Matchers.anyString())).thenAnswer(
        new Answer<Void>() {
            Void answer(InvocationOnMock invocation) {
                buffer.append((String)invocation.getArguments()[0]);
                return null;
            }
        });
    //... Inject the mock and do your test ...
    Assert.assertEquals("Hello, world!",buffer.toString());
}    

推荐