Mockito:如何模拟 XML 文档对象以从 XPath 检索值
Mockito: How to mock XML Document object to retrieve value from XPath
我正在尝试模拟一个 org.w3c.dom.Document 对象,这样调用 XPath.evaluate() 应该 return 一个定义的值,例如 foo,如下所示:
Document doc = Mockito.mock(Document.class);
Mockito.when(XPathUtils.xpath.evaluate("/MyNode/text()", doc, XPathConstants.STRING)).thenReturn("foo");
我会将 doc 对象传递给目标方法,该方法将提取节点 MyNode 的文本内容作为 foo。
我试过在 doc 对象中模拟节点和设置如下:
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 cannot
be returned by hasChildNodes() hasChildNodes() should return boolean
我的方法是否正确,我只是错过了另一个模拟,或者我应该采用不同的方法吗?请帮忙。
Don't mock types you don't own !,错了
为避免重复,这里有一个解释为什么
的答案
EDIT :我的意思是代码应该有可用的 builder 方法(在生产或测试类路径中)应该能够创建 real 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);
我习惯将此称为 "mocking" 文档,但它只是创建和使用一个真实的文档,然后将其用于模拟其他方法。您可以根据需要构造 document
的 xml 版本,或者使用其常规设置器来操作它以测试您的代码应该对文件执行的任何操作。您也可以用常量字符串替换读取文件的混乱,前提是它足够短以便于管理。
我正在尝试模拟一个 org.w3c.dom.Document 对象,这样调用 XPath.evaluate() 应该 return 一个定义的值,例如 foo,如下所示:
Document doc = Mockito.mock(Document.class);
Mockito.when(XPathUtils.xpath.evaluate("/MyNode/text()", doc, XPathConstants.STRING)).thenReturn("foo");
我会将 doc 对象传递给目标方法,该方法将提取节点 MyNode 的文本内容作为 foo。
我试过在 doc 对象中模拟节点和设置如下:
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 cannot be returned by hasChildNodes() hasChildNodes() should return boolean
我的方法是否正确,我只是错过了另一个模拟,或者我应该采用不同的方法吗?请帮忙。
Don't mock types you don't own !,错了
为避免重复,这里有一个解释为什么
EDIT :我的意思是代码应该有可用的 builder 方法(在生产或测试类路径中)应该能够创建 real 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);
我习惯将此称为 "mocking" 文档,但它只是创建和使用一个真实的文档,然后将其用于模拟其他方法。您可以根据需要构造 document
的 xml 版本,或者使用其常规设置器来操作它以测试您的代码应该对文件执行的任何操作。您也可以用常量字符串替换读取文件的混乱,前提是它足够短以便于管理。