Ever find yourself in need of a simple way to validate the structure and even the contents of generated XML? Here is one way of doing it:
public void testToXML() {
BatchDependencyXMLReport report =
new BatchDependencyXMLReport(new Date(9000000), this.getFilters());
report.addTargetAndDependencies("com.vanward.test.MyTest",
this.getDependencies());
report.addTargetAndDependencies("com.xom.xml.Test",
this.getDependencies());
String valid =
"<DependencyReport date="Wed Dec 31 21:30:00 EST 1969">"+
"<FiltersApplied><Filter pattern="java|org" />"+
"</FiltersApplied><Class name="com.vanward.test.MyTest">"+
"<Dependency name="com.vanward.xml.Element" /></Class>"+
"<Class name="com.xom.xml.Test">"+
"<Dependency name="com.vanward.xml.Element" />"+
"</Class></DependencyReport>";
assertEquals("report didn't match xml", valid, report.toXML());
}
This is as brute force as it gets. This test case works too, but if the document structure changes, someone’s got to update that nasty String.
Thankfully, there is a better way to do this. XMLUnit is a JUnit extension (there is also a .NET equivalent) that provides a nifty API for validating the structure of XML documents and their contents. Via its Diff class, the validation is also more flexible than that of straight String comparisons.
One can use XMLUnit via extending its XMLTestCase or via composition. Either way, however, you must properly configure it. This is easily done by creating a fixture as shown below:
protected void setUp() throws Exception {
XMLUnit.setControlParser(
"org.apache.xerces.jaxp.DocumentBuilderFactoryImpl");
XMLUnit.setTestParser(
"org.apache.xerces.jaxp.DocumentBuilderFactoryImpl");
XMLUnit.setSAXParserFactory(
"org.apache.xerces.jaxp.SAXParserFactoryImpl");
XMLUnit.setIgnoreWhitespace(true);
}
Now we can rewrite the previous test case and utilize the Diff class.
public void testToXML() throws Exception{
BatchDependencyXMLReport report =
new BatchDependencyXMLReport(new Date(9000000), this.getFilters());
report.addTargetAndDependencies(
"com.vanward.test.MyTest", this.getDependencies());
report.addTargetAndDependencies(
"com.xom.xml.Test", this.getDependencies());
Diff diff = new Diff(new FileReader(
new File("./test/conf/report-control.xml")),
new StringReader(report.toXML()));
assertTrue("XML was not identical", diff.identical());
}
Note, however, that by using XMLUnit, our test cases can end up being a bit more dependent on aspects out of their control. In this case, the test case depends on the file system- the report-control.xml file is read in and used for comparison purposes. Because of this outside dependency, XMLUnit tests are usually not true unit tests, but component tests.
To validate the structure of XML (meaning attribute values are ignored), XMLUnit offers the ability to use various listeners within the Diff class. The aptly named IgnoreTextAndAttributeValuesDifferenceListener effectively ignores the data in an XML document and simply validates the structure. Using this listener is quite simple:
public void testToXMLFormatOnly() throws Exception{
BatchDependencyXMLReport report =
new BatchDependencyXMLReport(new Date(), this.getFilters());
report.addTargetAndDependencies(
"com.vanward.test.MyTest", this.getDependencies());
report.addTargetAndDependencies(
"com.xom.xml.Test", this.getDependencies());
Diff diff = new Diff(new FileReader(
new File("./test/conf/report-control.xml")),
new StringReader(report.toXML()));
//setting this difference listener will ingore ALL attr values
diff.overrideDifferenceListener(
new IgnoreTextAndAttributeValuesDifferenceListener());
assertTrue("XML was not similar", diff.similar());
}
The next time the task of validating an application’s generated XML comes up, consider using XMLUnit.
