Backend Development 12 min read

Using XMLUnit for Java XML Testing: From String Comparison to Advanced Diff and XPath Validation

The article explains why simple String comparison is insufficient for XML validation, introduces the Java‑based XMLUnit library, and demonstrates how to use it with JUnit/TestNG, Diff, and XPath to reliably test XML structure, content, and specific values.

Qunar Tech Salon
Qunar Tech Salon
Qunar Tech Salon
Using XMLUnit for Java XML Testing: From String Comparison to Advanced Diff and XPath Validation

During a software development cycle it is often necessary to verify the structure and content of XML documents, but doing so with plain String comparison is fragile and hard to maintain.

Typical String‑based tests compare the generated XML against a hard‑coded String (see List 1), which only checks that the application can produce a document but not its correctness.

public class XMLReportTest extends TestCase { private Filter[] getFilters(){ Filter[] fltrs = new Filter[2]; fltrs[0] = new RegexPackageFilter("java|org"); fltrs[1] = new SimplePackageFilter("net."); return fltrs; } private Dependency[] getDependencies(){ Dependency[] deps = new Dependency[2]; deps[0] = new Dependency("com.acme.resource.Configuration"); deps[1] = new Dependency("com.acme.xml.Document"); return deps; } public void testToXML() { Date now = new Date(); BatchDependencyXMLReport report = new BatchDependencyXMLReport(now, this.getFilters()); report.addTargetAndDependencies("com.acme.web.Widget", this.getDependencies()); report.addTargetAndDependencies("com.acme.web.Account", this.getDependencies()); String valid = "<DependencyReport date=\"" + now.toString() + "\">" + "<FiltersApplied><Filter pattern=\"java|org\" /><Filter pattern=\"net.\" />" + "</FiltersApplied><Class name=\"com.acme.web.Widget\">" + "<Dependency name=\"com.acme.resource.Configuration\" />" + "<Dependency name=\"com.acme.xml.Document\" /></Class>" + "<Class name=\"com.acme.web.Account\">" + "<Dependency name=\"com.acme.resource.Configuration\" />" + "<Dependency name=\"com.acme.xml.Document\" />" + "</Class></DependencyReport>"; assertEquals("report didn't match xml", valid, report.toXML()); } }

This approach is unreadable, extremely brittle (any whitespace change breaks the test), and forces the test to deal with dates.

XMLUnit, a JUnit extension written for Java developers, can be used with TestNG as well; it provides APIs for comparing XML documents, checking structure, content, and specific parts.

Basic usage involves configuring parsers and creating a Diff object to compare a generated XML document with a control file:

public class XMLReportTest extends TestCase { 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); } // getFilters() and getDependencies() omitted for brevity public void testToXML() { BatchDependencyXMLReport report = new BatchDependencyXMLReport(new Date(1165203021718L), this.getFilters()); report.addTargetAndDependencies("com.acme.web.Widget", this.getDependencies()); report.addTargetAndDependencies("com.acme.web.Account", 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()); } }

Calling XMLUnit.setIgnoreWhitespace(true) is essential to avoid failures caused by insignificant whitespace.

The Diff class supports two comparison modes: identical (exact match) and similar (same logical structure but possibly different ordering or whitespace). Example XML fragments illustrate the difference.

public void testIdenticalAndSimilar() throws Exception { String controlXML = "<account><id>3A-00</id><name>acme</name></account>"; String testXML = "<account><name>acme</name><id>3A-00</id></account>"; Diff diff = new Diff(controlXML, testXML); assertTrue(diff.similar()); assertFalse(diff.identical()); }

To validate only the XML structure while ignoring element text and attribute values, one can override the difference listener with IgnoreTextAndAttributeValuesDifferenceListener :

public void testToXMLFormatOnly() throws Exception { BatchDependencyXMLReport report = new BatchDependencyXMLReport(new Date(), this.getFilters()); // add targets omitted Diff diff = new Diff(new FileReader(new File("./test/conf/report-control.xml")), new StringReader(report.toXML())); diff.overrideDifferenceListener(new IgnoreTextAndAttributeValuesDifferenceListener()); assertTrue("XML was not similar", diff.similar()); }

XPath can be combined with XMLUnit to assert specific values without full document comparison. Extending XMLTestCase provides helper methods such as assertXpathExists :

public void testXPathValue() throws Exception { BatchDependencyXMLReport report = new BatchDependencyXMLReport(new Date(), this.getFilters()); report.addTargetAndDependencies("com.acme.web.Widget", this.getDependencies()); assertXpathExists("//Class[1][@name='com.acme.web.Widget']", report.toXML()); }

Overall, XMLUnit offers a robust, open‑source solution for Java XML testing, eliminating the pitfalls of raw String comparison while supporting structural, content, and XPath‑based validations.

JavaJunitxpathDiffXML TestingXMLUnit
Qunar Tech Salon
Written by

Qunar Tech Salon

Qunar Tech Salon is a learning and exchange platform for Qunar engineers and industry peers. We share cutting-edge technology trends and topics, providing a free platform for mid-to-senior technical professionals to exchange and learn.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.