Java 模拟输出流#刷新方法
我有:我有服务类的方法Java 模拟输出流#刷新方法,java,unit-testing,mockito,java-io,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); o
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方法
?您当前的代码无法工作:
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
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();
}
您可能希望在此处查看关闭输出流的决定,而不是在打开输出流的同一块中执行
现在,您可以通过让单元测试提供OutputStream来测试它
@Test
public void testPullAndFlushData() {
URI uri = ...;
Params params = ...;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
someObject.pullAndFlushData(baos, uri, params);
assertSomething(..., baos.toByteArray());
}
@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,但它是测试使用OutputStream的方法的一个好模式
@Test
public void testPullAndFlushData() {
URI uri = ...;
Params params = ...;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
someObject.pullAndFlushData(baos, uri, params);
assertSomething(..., baos.toByteArray());
}
@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模拟输出流,并以相同的方式使用它——为调用它的write()
调用设置期望值。但是copyragle()
对数据进行分块的方式会变得非常脆弱
您还可以使用Mockito的spy()
来检查是否对真实的ByteArrayOutputStream进行了调用
@Test
public void testPullAndFlushData() {
URI uri = ...;
Params params = ...;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
someObject.pullAndFlushData(baos, uri, params);
assertSomething(..., baos.toByteArray());
}
@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()
,而且在大多数情况下,他们认为这不是一种好的测试方法。阅读以了解原因。如果您接受一个OutputStream
作为方法的参数,您可以通过通过通过tearrayoutputstream传递一个并测试内容来测试该方法。我看不到用当前代码进行模拟的机会。注意:您的方法没有做任何有用的事情。我想这是因为你简化了这个问题。我认为你过于简化了它,这将使我们更难建议如何测试它。@Duncan我不接受OutputSteam
作为我方法的参数IOUtils
是第三方谷歌class@Duncan它从某些服务获取数据,并将其保存到文件中。是的,它可以修改两个操作的数据。但在这种情况下,这真的无关紧要。我建议你应该添加一个论点。有时,您的代码需要更改以使其能够进行测试。+1这正是我所想的。(虽然我很懒,写了一条评论,但这不是一个好的答案)。我几乎会考虑删除你最后几段——我们不希望新用户认为这是一个很好的测试方法。邓肯说,他确实想检查FrHuSE()。我要说的是Mockito团队不同意。