Introduction
XPath assertions allow you to unit-test code that returns or emits XML. This is useful anywhere from web applications to XML generating code.
Background
XPath is a XML-query standard. You use XPath to retrieve XML nodes - elements or attributes. You can think of XPath as a SQL query with a limited feature-set. XPath syntax is well documents here.
.NET supports XPath version 1.0 queries through it's System.Xml.Xpath namespace.
In this article I'm presenting a class that encapsulates XPath assertions for MS .NET unit-testing framework. It can easily be converted to use other unit-testing frameworks.
I've used unit-testing extensively when writing a client-server application where both ends communicate XML documents. The presented code allowed me to test each side separately and has saved me much work. I hope you'll find it useful!
Using the code
XpathAssert
class exposes static methods which you call to assert the XPath expressions. The method in the heart of this class which all other methods use retrieves an iterator over the result set of an XPath expression:
private static XPathNodeIterator GetIterator(XmlDocument xDoc, string xpath)
{
XPathNavigator xNav = xDoc.CreateNavigator();
XPathNodeIterator xItr = xNav.Select(xpath);
return xItr;
}
The other methods are merely wrappers around this method. For example this method will fail if the XPath query yields an unexpected node count:
public static XPathNodeIterator NodeCountEquals(XmlDocument xDoc, string xpath, int expectedCount)
{
XPathNodeIterator xItr = GetIterator(xDoc, xpath);
Assert.AreEqual(expectedCount, xItr.Count,
string.Format("Xpath expression '{0}' was expected to return {1} results", xpath, expectedCount));
return xItr;
}
The following method will fail if the XPath query yields results with unexpected child elements:
public static void LegitimateChildren(XmlDocument xDoc, string elemKidsXpath, params string[] legitimateChildren)
{
Assert.IsNotNull(legitimateChildren);
string allowedKids = string.Format("[name()!='{0}'", legitimateChildren[0]);
for (int i = 1; i < legitimateChildren.Length; ++i)
{
allowedKids += string.Format("and name()!='{0}'", legitimateChildren[i]);
}
string xpath = elemKidsXpath + allowedKids + "]";
NodeCountEquals(xDoc, xpath, 0);
}
As you see this method modifies the query to count child-elements with unexpected names. The assertion tests if the result count is 0.
Now lets look at some XPath assertions:
XpathAssert.NodeCountEquals(xmlDoc, "//updatecheck/urls/url", expectedUrlList.Count);
XpathAssert.LegitimateChildren(xmlDoc, "/response/*", "daystart", "app");
XpathAssert.NodeCountEqual(xmlDoc, "//ping", "//app/ping");
XpathAssert.NodeCountMin(xmlDoc, "//urls[count(/*)=0]", 0);
Points of Interest
This class is one of several I've implemented to extend MS standard unit-testing framework. In subsequent articles I'll provide more classes.