模拟OutputStream#flush方法

时间:2014-06-17 09:42:29

标签: java unit-testing mockito java-io

我有:我有方法void服务类方法。此方法从远程获取一些数据,然后用OutputStream刷新它们。

public void pullAndFlushData(URI uri, Params params) {
  InputStream input = doHttpRequest(uri, params);
  OutputStream output = new OutputStream("somepath");
  IOUtils.copyLarge(input, output);
  output.flush();
  output.close();
}

我想:测试此方法的结果。所以我想模拟output.flush()并检查它是否包含正确的数据。

问题:如何模仿OutputStream#flush method

1 个答案:

答案 0 :(得分:2)

您当前的代码无效:

 OutputStream output = new OutputStream("SomePath");

...将无法编译,因为OutputStream是抽象的。

所以在某个地方你需要告诉方法要使用什么OutputStream。为了使其更易于测试,请将流设为参数。

 public void pullAndFlushData(OutputStream output, URI uri, Params params) {
    InputStream input = doHttpRequest(uri, params);
    IOUtils.copyLarge(input, output);
    output.flush();
    output.close();
 }

或者,output可以是对象中的一个字段,由构造函数或setter填充。或者您可以将对象传递给工厂。无论您选择哪种方式,都意味着调用者可以控制使用哪种OutputStream - 对于生产代码,FileOutputStream;对于测试,ByteArrayOutputStream

您可能希望在此处查看close() OutputStream的决定 - 而是在打开OutputStream的同一块中执行此操作。

现在,您可以通过让您的单元测试提供OutputStream来测试它。

@Test
public void testPullAndFlushData() {
     URI uri = ...;
     Params params = ...;
     ByteArrayOutputStream baos = new ByteArrayOutputStream();
     someObject.pullAndFlushData(baos, uri, params);
     assertSomething(..., baos.toByteArray());
}

这不使用Mockito,但它是测试使用OutputStream的方法的好模式。

你可以让Mockito模拟一个OutputStream并以同样的方式使用它 - 设置write()调用它的期望值。但是,copyLarge()数据块的存储方式会变得非常脆弱。

您还可以使用Mockito的spy()来检查是否对您的真实ByteArrayOutputStream进行了调用。

@Test
public void testPullAndFlushData() {
     URI uri = ...;
     Params params = ...;
     ByteArrayOutputStream spybaos = spy(new ByteArrayOutputStream());
     someObject.pullAndFlushData(spybaos, uri, params);
     assertSomething(..., spybaos.toByteArray());
     verify(spybaos).flush(); // asserts that flush() has been called.
}

但请注意,Mockito团队非常不愿意提供spy(),并且在大多数情况下并不认为这是一种很好的测试方式。出于理由阅读Mockito docs