Mockito:如何模拟 XML 文档对象以从 XPath 检索值



我试图模拟一个org.w3c.dom.Document对象,这样调用XPath.evaluate()应该返回一个定义的值,例如foo,如下所示:

Document doc = Mockito.mock(Document.class);    
Mockito.when(XPathUtils.xpath.evaluate("/MyNode/text()", doc, XPathConstants.STRING)).thenReturn("foo");

我将把 doc 对象传递给目标方法,该方法将提取节点 MyNode 的文本内容作为 foo

我尝试在文档对象中模拟节点和设置,如下所示:

            Node nodeMock = mock(Node.class);
            NodeList list = Mockito.mock(NodeList.class);
            Element element = Mockito.mock(Element.class);
            Mockito.when(list.getLength()).thenReturn(1);
            Mockito.when(list.item(0)).thenReturn(nodeMock);
            Mockito.when(doc.getNodeType()).thenReturn(Node.DOCUMENT_NODE);
            Mockito.when(element.getNodeType()).thenReturn(Node.ELEMENT_NODE);
            Mockito.when(nodeMock.getNodeType()).thenReturn(Node.TEXT_NODE);
            Mockito.when(doc.hasChildNodes()).thenReturn(false);
            Mockito.when(element.hasChildNodes()).thenReturn(true);
            Mockito.when(nodeMock.hasChildNodes()).thenReturn(false);
            Mockito.when(nodeMock.getNodeName()).thenReturn("MyNode");
            Mockito.when(nodeMock.getTextContent()).thenReturn("MyValue");
            Mockito.when(element.getChildNodes()).thenReturn(list);
            Mockito.when(doc.getDocumentElement()).thenReturn(element);

但这给出了这样的错误:

org.mockito.exceptions.misusing.WrongTypeOfReturnValue: String 不能 由 hasChildNodes() 返回 hasChildNodes() 应该返回布尔值

的方法是否正确,我错过了另一个模拟,还是我应该以不同的方式处理它?请帮忙。

不要嘲笑你不拥有的类型!,这是错误的。

为了避免重复,这里有一个答案可以解释为什么 https://stackoverflow.com/a/28698223/48136

编辑:我的意思是代码应该具有可用的构建器方法(在生产或测试类路径中),无论该文档的来源如何,都应该能够创建一个真正的Document,但肯定不是模拟。

例如,此工厂方法或构建器可以通过以下方式使用DocumentBuilder

class FakeXMLBuilder {
    static Document fromString(String xml) {
        DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
        return dBuilder.parse(new ByteArrayInputStream(xml.getBytes("UTF_8")));
    }
}

当然,这必须根据项目的需要量身定制,并且可以进行更多定制。在我目前的项目中,我们有很多测试构建器可以创建对象、json 等。例如:

Leg leg      = legWithRandomId().contact("Bob").duration(234, SECONDS).build();
String leg   = legWithRandomId().contact("Bob").duration(234, SECONDS).toJSON();
String leg   = legWithRandomId().contact("Bob").duration(234, SECONDS).toXML();
Whatever leg = legWithRandomId().contact("Bob").duration(234, SECONDS).to(WhateverFactory.whateverFactory());

Jsoup.parse()与测试 XML 字符串一起使用。像下面这样的东西应该可以工作,用于测试我假设testClassInstance.readFromConnection(String url)的一些实例方法:

// Turn a block of XML (static String or one read from a file) into a Document
Document document = Jsoup.parse(articleXml);
// Tell Mockito what to do with the Document
Mockito.when(testClassInstance.readFromConnection(Mockito.any()))
  .thenReturn(document);

我习惯于将其称为"模拟"文档,但它只是创建和使用真实的文档,然后将其用于模拟其他方法。您可以随心所欲地构造 document 的 xml 版本,也可以使用其常规资源库来操作它以测试您的代码应该对文件执行的任何操作。你也可以用一个常量字符串替换读取文件的混乱,只要它足够短,便于管理。

最新更新