模拟Java InputStream


77

请提供指针以帮助我模拟该java InputStream对象。这是我希望模拟的代码行:

InputStreamReader inputData = new InputStreamReader(System.in);
bufferdReader = new BufferedReader(inputData);
bufferdReader.readLine(); 

1
您的问题是System.in吗?您可能希望重构代码,以便传递另一个InputStream而不是System.in; 那么您可以使用任何模拟框架(如答案中提到的)来模拟此InputStream。
phtrivier

Answers:


59
BufferedReader bufferedReader = org.mockito.Mockito.mock(BufferedReader.class);
when(bufferedReader.readLine())
  .thenReturn("first line")
  .thenReturn("second line");

org.junit.Assert.when(new Client(bufferedReader).parseLine())
  .thenEquals(IsEqual.equalTo("first line"));

感谢您的快速回复。.将检查它
Reji 2011年

如何导入Client?抱歉,但是我是mockito和junit的新手,您正在此行上使用Client:org.junit.Assert.when(new Client(bufferedReader).parseLine())
Alejandro Sanchez,

客户端是使用缓冲的读取器逐行读取并解析它的类
BorisPavlović19/

109

您可以使用commons-io创建一些存根输入流:

InputStream stubInputStream = 
     IOUtils.toInputStream("some test data for my input stream", "UTF-8");

1
如果要多次使用流,使用后如何重置?
exic

您可以将其包装在BufferedInputStream中,并使用mark()和reset()。但是在您的设置方法中实例化一个新方法可能会更容易(假设我们在这里仍在谈论测试)。
Eric

1
从v2.3开始,您需要添加字符集,例如:toInputStream("someString", "UTF-8")。不推荐使用仅String作为参数的版本。
JonyD

谢谢@JonyD!我更新了答案以包括charset参数。
艾瑞克(Eric)

我最喜欢的答案!我只想补充一点,而不是使用非类型安全的字符串,您可以使用StandardCharsets.UTF_8
dcasadevall

98

您可以只使用aByteArrayInputStream并用测试数据填充它。

@Brad的示例来自评论:

InputStream anyInputStream = new ByteArrayInputStream("test data".getBytes());

额外的好处是ByteArrayInputStream支持mark()reset()
Hank

5
漂亮又简单……InputStream anyInputStream = new ByteArrayInputStream("test data".getBytes());
布拉德(Brad)

20

我不同意这个问题的答案。像Mockito这样的Mocking框架都很不错,但是当标准的Java api可用时,您可以考虑使用它。

BufferedReader reader = new BufferedReader(new StringReader("some string"));

当您可以在状态类和行为类中使用真实对象时,为什么还要在测试类中使用Mock对象呢?

要了解有关其工作原理的更多信息,可以查找“装饰器”设计模式。


3
这是一个用例:模拟多个不同的调用,例如在循环中(错误的输入1->错误的输入2->正确的输入3)。
2014年

就像Java api一样,将InputStream代码和Reader代码放在单独的类中。让您的测试类通过Reader而不是InputStream的实现,并在生产代码中将Reader的实现传递给正在读取数据/进行数据处理的类。
John Deverall

3

更改对象,以便于测试,例如:

public MyObject {
    private InputStream inputStream;

    public void setInputStream(InputStream inputStream) {this.inputStream = inputStream;}

    public void whatever() {
        InputStreamReader inputData = new InputStreamReader(inputStream);
        bufferdReader = new BufferedReader(inputData);
        bufferdReader.readLine(); 
    }
}

然后,当您使用对象时,请首先初始化其inputStream:

MyObject myObject = new MyObject();
myObject.setInputStream(System.in);

现在,您有了一个对象,可以在其中使用所需的InputStream的任何实现对其进行测试(ByteArrayInputStream是一个不错的尝试)。


2
@Test
    public void testReadFile() {
    TestClass ClassName = Mockito.mock(TestClass.class);
     InputStream in = Mockito.mock(InputStream.class);
     InputStreamReader inr =Mockito.mock(InputStreamReader.class);
     BufferedReader bufferedReader =Mockito.mock(BufferedReader.class);
       try {
         PowerMockito.whenNew(InputStreamReader.class).withArguments(in).thenReturn(inr);
         PowerMockito.whenNew(BufferedReader.class).withArguments(inr).thenReturn(bufferedReader);
         String line1 = "example line";
         PowerMockito.when(bufferedReader.readLine()).thenReturn(line1).thenReturn(null);
         method return type = Whitebox.invokeMethod(ClassName, "MethodName", arguement);
         assertEquals("result is::","expected", actual);
     } catch (Exception e) {
         e.printStackTrace();
     }
 }

2
String testString = "test\nstring";
InputStream stream = new ByteArrayInputStream(testString.getBytes(StandardCharsets.UTF_8));

BufferedReader reader = new BufferedReader(new InputStreamReader(stream));

Assert.assertEquals("test", reader.readLine());
Assert.assertEquals("string", reader.readLine());

1

我发现的最佳解决方案是使用

final InputStream inputStream1 = IOUtils.toInputStream("yourdata");

然后将inpustream包装在bufferedReader中,以最佳方式围绕输入Stream编写测试


1
这增加了对IOUtils的依赖-使您的测试代码更大。这不是我们希望从小型单元测试获得的理想效果……
IgorGanapolsky

0

假设您正在使用Maven,则可以将资源放入“ src / test / resources /”文件夹中,比如说“ src / test / resources / wonderful-mock-data.xml ”。然后在您的jUnit中可以执行以下操作:

    String resourceInputFile = "/database-insert-test.xml";
    URL url = this.getClass().getResource(resourceInputFile);
    Assert.assertNotNull("Can't find resource " + resourceInputFile, url);

    InputStream inputStream = url.openStream();

    // Now you can just use the inputStream for method calls requiring this param
    (...)

在此示例中,如果在当前类路径中找不到给定资源,则url varialble将为null。这种方法允许您将多个方案放在不同的resourceInputFile(s)中。还要记住,所有类型的资源都在“ src / test / resources /”下(不仅是xml文件,还包括txt,html,jpeg等任何类型)。 )通常可以从所有jUnit测试中用作类路径资源。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.