我有:我有方法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
?
答案 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。