java - 在单元测试中的 Java 中,使用 Mockito,如何模拟对 XML DocumentBuilder 的调用,使其不返回 FileNotFoundException
问题描述
我想对一个函数进行单元测试,该函数除其他外调用另一个从磁盘读取 XML 文件的私有函数。在单元测试中,我不想依赖磁盘上的真实文件,而是想使用保存在 String 变量中的 XML。
我尝试同时模拟DocumentBuilder
and DocumentBuilderFactory
,但没有成功,因为DocumentBuilder
仍然想从磁盘读取文件,因此在单元测试中给出FileNotFoundException
.
我想避免使用 PowerMockito。
下面是一个简短的代码片段,我可以用它来重现这个问题。
正在测试的类:
public class XMLReader {
private void readXml() throws IOException {
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder;
try {
docBuilder = docFactory.newDocumentBuilder();
Document doc = docBuilder.parse("path/to/xml");
} catch (ParserConfigurationException | SAXException e) {}
}
public boolean functionForTest() throws IOException {
readXml();
return true;
}
}
这是我的测试课:
public class AppTest {
private static final String CLUSTER_CONF_XML = "<element></element>";
private static Document buildXmlFromString(String xml) throws ParserConfigurationException, IOException, SAXException {
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
return dBuilder.parse(new ByteArrayInputStream(xml.getBytes(Charset.defaultCharset())));
}
@org.junit.Test
public void testFunctionForTest() throws ParserConfigurationException, SAXException, IOException {
DocumentBuilderFactory documentBuilderFactory = Mockito.mock(DocumentBuilderFactory.class);
DocumentBuilder xmlDocumentBuilder = Mockito.mock(DocumentBuilder.class);
try {
Mockito.when(documentBuilderFactory.newDocumentBuilder()).thenReturn(xmlDocumentBuilder);
Document doc = buildXmlFromString(CLUSTER_CONF_XML);
Mockito.when(xmlDocumentBuilder.parse(Mockito.anyString())).thenReturn(doc);
} catch (IOException e) {}
XMLReader xmlReader = new XMLReader();
boolean result = xmlReader.functionForTest();
assertEquals(result, true);
}
}
在运行我收到的测试时FileNotFoundException
,而预期的行为会模拟 XML,其中 XML 的内容保存在进行模拟时在测试中使用的 String 变量中,从而避免异常和测试用例通过。
预先感谢您的帮助。
解决方案
您的问题非常简单:您的实例XMLReader
是从“真实”依赖项中调用方法,而不是从您制作的模拟中调用方法。你忘了“注入模拟”。
我会建议一个简单(虽然不干净)的解决方案,但您应该考虑重新设计可测试性:
- 重构您的
XMLReader
,以便它接收DocumentBuilder
作为构造函数的参数的依赖项。 DocumentBuilder
此外,不要在您的方法上实例化 new,而是readXml()
使用您通过构造函数注入的依赖项的引用。- 最后,当您
XMLReader
在测试用例上实例化时,使用注入我提到的依赖项的构造函数(使用您刚刚制作的模拟)。然后,每当从该readXml()
方法进行调用时,它都会从模拟中调用。
例子:
public class XMLReader {
private DocumentBuilder documentBuilder;
private void readXml() throws IOException {
try {
Document doc = docBuilder.parse("path/to/xml");
} catch (ParserConfigurationException | SAXException e) {}
}
public boolean functionForTest() throws IOException {
readXml();
return true;
}
public XMLReader(DocumentBuilder documentBuilder) {
this.documentBuilder = documentBuilder;
}
}
推荐阅读
- haskell - 如何在一定数量的递归调用后停止函数?
- c++ - 错误“lambda 不是从 'std::function' 派生的
- reactjs - 如何修复 NextJS 中的“TypeError:无法读取未定义的属性“id”错误?
- java - 当在同一流管道中使用的终端操作不遵守顺序时,中间操作是否遵守顺序?
- javascript - 如何导航到不在选项卡导航器中的 react native 页面?
- python - 如何更新odoo中所有产品的字段中的不同记录?
- dns - spf记录中的减号是什么
- mysql - 如何按特定标准进行分组和计数?
- python - 使用两个不同的拆分将字符串分成二维数组
- java - 当循环为真时,如何仅添加到总数中?