如何在Java中模拟Inputstream以加载属性

如何在Java中模拟Inputstream以加载属性,java,android,inputstream,junit4,Java,Android,Inputstream,Junit4,我想测试properties.load(in)方法抛出的IOException和IllegalArgumentException。根据OracleDoc这里的文档,如果读取输入流时发生错误,load方法会抛出IOExceptionIllegalArgumentException-如果输入流包含格式错误的Unicode转义序列 这是我的密码: public class PropertiesRetriever { private String foo; private String foo1; p

我想测试
properties.load(in)
方法抛出的
IOException
IllegalArgumentException
。根据OracleDoc这里的文档,如果读取输入流时发生错误,load方法会抛出
IOException
IllegalArgumentException
-如果输入流包含格式错误的Unicode转义序列

这是我的密码:

public class PropertiesRetriever {

private String foo;
private String foo1;
private Properties properties;

/**
 * Injects the properties file Path in the {GuiceModule}
 * Calls {@link PropertiesRetriever#loadPropertiesPath(String) to load the
 * properties file.
 */

@Inject
public PropertiesRetriever(@Named("propertiesPath") String propertiesPath,     Properties properties)
   throws IOException {
this.properties = properties;
loadPropertiesPath(propertiesPath);
}

/**
 * Loads the properties file as inputstream.
 * 
 */
public void loadPropertiesPath(String path) throws IOException {
InputStream in = this.getClass().getResourceAsStream(path);
properties.load(in);

}
这里有一种方法:

 properties.load(in)

抛出
IOException
IllegalArgumentException
。我想在JUnit测试中测试这个方法。无论如何,我都可以调用这些方法。

您有两个选择。要么提供一些将创建预期错误的测试文件,要么将流的模拟作为参数传递给属性检索器。因此,您将直接使用inputStream而不是propertiesPath参数(这种方法可能会将您的问题转移到其他地方)


如果您决定将流作为参数传递,那么有一些技巧,如何模拟它:

您可以通过稍微重构代码来实现。然后使用Mockito或其他模拟框架创建一个行为符合您要求的InputStream(抛出异常):

你可以用mockito来定义你的物体的形状;mock
getIStream(String)
返回模拟
InputStream
。设置模拟以在调用
InputStream::read(byte[])
时引发所需的异常

如果您不想使用PowerMock,那么可以将
getIStream(String)
的可见性更改为
default
。然后,普通的mockito将完成这项工作:

@Test
public void exceptionTest() throws IOException {
    PropertiesRetriever pr = new PropertiesRetriever();
    PropertiesRetriever prSpy = spy(pr);

    InputStream isMock = mock(InputStream.class);
    doReturn(isMock).when(prSpy).getIStream(anyString());

    doThrow(new IllegalArgumentException("CRASH!")).when(isMock).read(any());

    prSpy.loadPropertiesPath("blah");
}

可能的重复我实际上试图避免使用PowerMock或Matchers.any()我计划只使用Mockito。它仍然没有抛出IOException或IllegalArgumentException。我是否可以创建损坏的Inputstream?还是我在这里遗漏了什么?@Jasmine,您可以在
doThrow()
中指定所需的异常。在我的示例中,我使用了一个
IllegalArgumentException
,但您也可以抛出
IOException
及其子类或任何
RuntimeException
。我可以模拟我正在测试的类吗?指定的方法模拟要测试的类。这有效吗?@Jasmine是的。它在Mockito行话中被称为部分模拟或“间谍”。我通过了InputStream的模拟,但它仍然没有抛出IOException。有什么方法可以测试这个吗?如果我使用ArgumentCaptor捕获Inputstream.class并使用doThrow(IOException.class).when(mockProperties).load(reqCaptor.capture())会是一个好主意吗;最后调用gitubPropertiesRetreiver.loadPropertiesPath(filePath);然后检查IOException?
@Test
public void exceptionTest() throws IOException {
    PropertiesRetriever pr = new PropertiesRetriever();
    PropertiesRetriever prSpy = spy(pr);

    InputStream isMock = mock(InputStream.class);
    doReturn(isMock).when(prSpy).getIStream(anyString());

    doThrow(new IllegalArgumentException("CRASH!")).when(isMock).read(any());

    prSpy.loadPropertiesPath("blah");
}