XML Assert
Small library for those who have a hard time understanding the complexity of XPath.
Rationale
Have you ever met such a XPath expression?
/root[matches(property1, concat('',"'",'"<>\[\]\(\)'))]
Pretty isn’t it? Wouldn’t it be better to just read:
assertThat(xml).node("root").node("property1").matches('\'"<>\\[\\]\\(\\)')
XMLAssert to the rescue!
Fast intro
Assertions
The library has a couple of main classes. One is XmlAssertion
that gives you public static methods:
public static XmlVerifiable assertThat(String xml)
NOTE! The aforementioned version caches the Document
for the provided XML.
and
public static XmlVerifiable assertThat(org.w3c.dom.Document parsedXml)
Both these methods give return the public XmlVerifiable
interface which is a fluent interface with which you can build your XPath expression. Please check the Javadocs of that file for more information.
Building XPaths
As you could see it’s not that easy to build a XPath. With XMLAssert you can use the XPathBuilder
class to finally build the XPaths yourself! This is the contract for the XPathBuilder
class:
/**
* Returns a builder of {@link XmlVerifiable} with which you can build your
* XPath. Once finished just call {@link XmlVerifiable#xPath()} to get
* XPath as String.
*/
public static XmlVerifiable builder()
and when you call:
XPathBuilder.builder().node("some").node("nested").array("withlist").contains("name").isEqualTo("name1").xPath();
you will receive /some/nested/withlist[name='name1']
String.
Retrieving XPath value
Wouldn’t it be great to retrieve the value from the XML via the XPath? There you go!
Note
|
It works only for String values |
def 'should resolve the value of XML via XPath'() {
given:
String xml =
'''<?xml version="1.0" encoding="UTF-8" ?>
<root>
<element>
<some>
<nested>
<json>with value</json>
<anothervalue>4</anothervalue>
<withlist>
<name>name1</name>
</withlist>
<withlist>
<name>name2</name>
</withlist>
<withlist>
<anothernested>
<name>name3</name>
</anothernested>
</withlist>
</nested>
</some>
</element>
<element>
<someother>
<nested>
<json>true</json>
<anothervalue>4</anothervalue>
<withlist>
<name>name1</name>
</withlist>
<withlist>
<name>name2</name>
</withlist>
<withlist2>a</withlist2>
<withlist2>b</withlist2>
</nested>
</someother>
</element>
</root>'''
expect:
XPathBuilder.builder(xml).node("root").array("element").node("some").node("nested").node("json").read() == 'with value'
XPathBuilder.builder(xml).node("root").array("element").node("some").node("nested").node("anothervalue").read() == 4.toString()
assertThat(xml).node("root").array("element").node("someother").node("nested").node("json").read() == true.toString()
}
All thanks to the XmlReader
interface:
/**
* Returns the value from the XML, based on the created XPath.
*/
String read();
How to add it
Just add it as your dependency (Example for Gradle)
testCompile 'com.toomuchcoding.xmlassert:xmlassert:0.0.2'
Dependencies
XMLAssert is really lightweight. It depends only on:
compile 'com.rackspace.eclipse.webtools.sourceediting:org.eclipse.wst.xml.xpath2.processor:2.1.100'
compile 'xerces:xercesImpl:2.11.0'
compile "ch.qos.logback:logback-classic:1.1.2"
Examples
Example 1
For the XML
<?xml version="1.0" encoding="UTF-8" ?>
<some>
<nested>
<json>with "val'ue</json>
<anothervalue>4</anothervalue>
<withattr id="a" id2="b">foo</withattr>
<withlist>
<name>name1</name>
</withlist>
<withlist>
<name>name2</name>
</withlist>
<withlist>
8
</withlist>
<withlist>
<name id="10" surname="kowalski">name3</name>
</withlist>
</nested>
</some>
The following is true
XMLAssert expressions:
assertThat(xml1).node("some").node("nested").node("anothervalue").isEqualTo(4)
assertThat(xml1).node("some").node("nested").node("anothervalue")
assertThat(xml1).node("some").node("nested").node("withattr").withAttribute("id", "a").withAttribute("id2", "b")
assertThat(xml1).node("some").node("nested").node("withattr").isEqualTo("foo").withAttribute("id", "a").withAttribute("id2", "b")
assertThatXml(xml1).node("some").node("nested").node("anothervalue").isEqualTo(4)
assertThat(xml1).node("some").node("nested").array("withlist").contains("name").isEqualTo("name1")
assertThat(xml1).node("some").node("nested").array("withlist").contains("name").isEqualTo("name2")
assertThat(xml1).node("some").node("nested").array("withlist").contains("name").isEqualTo("name3").withAttribute("id", "10").withAttribute("surname", "kowalski")
assertThat(xml1).node("some").node("nested").array("withlist").isEqualTo(8)
assertThat(xml1).node("some").node("nested").node("json").isEqualTo("with \"val'ue")
assertThat(xml1).node("some", "nested", "json").isEqualTo("with \"val'ue")
Respective XPath expressions:
/some/nested[anothervalue=4]
/some/nested/anothervalue
/some/nested/withattr[@id='a'][@id2='b']
/some/nested[withattr='foo']/withattr[@id='a'][@id2='b']
/some/nested[anothervalue=4]
/some/nested/withlist[name='name1']
/some/nested/withlist[name='name2']
/some/nested/withlist[name='name3']/name[@id='10'][@surname='kowalski']
/some/nested/withlist[number()=8]
/some/nested[json=concat('with "val',"'",'ue')]
/some/nested[json=concat('with "val',"'",'ue')]
More examples
More examples can be found in the XmlAssertionSpec
in the test sources
Additional features
AssertJ integration
There is a possibility to use XMLAssert via AssertJ. Regardless of which version you’ll choose you have the same class that you can use to start the fluent assertion.
The standard version
com.toomuchcoding.xmlassert.XmlAssertions.assertThat(Document context);
com.toomuchcoding.xmlassert.XmlAssertions.assertThat(XmlAsString xmlAsString);
com.toomuchcoding.xmlassert.XmlAssertions.assertThat(XmlVerifiable xmlVerifiable);
or the BDD version
com.toomuchcoding.xmlassert.BDDXmlAssertions.then(Document context);
com.toomuchcoding.xmlassert.BDDXmlAssertions.then(XmlAsString xmlAsString);
com.toomuchcoding.xmlassert.BDDXmlAssertions.then(XmlVerifiable xmlVerifiable);
AssertJ 2.x
Just add
testCompile 'com.toomuchcoding.xmlassert:xmlassert-assertj-java7:0.0.2'
AssertJ 3.x
Just add
testCompile 'com.toomuchcoding.xmlassert:xmlassert-assertj-java8:0.0.2'