CompareAssert - xmlunit/user-guide GitHub Wiki
XMLUnit for Java provides an AssertJ assert class named CompareAssert
.
Access to CompareAssert is provided by XmlAssert.and(Object)
method.
The method allows to define test- and control- XML sources
that can be compared with each other.
There are two XMLUnit modules supporting AssertJ. xmlunit-assertj
supports AssertJ 2.x and 3.x while xmlunit-assertj3
requires at
least AssertJ 3.18.1. The examples here assume xmlunit-assertj
, with
xmlunit-assertj3
the Java package has to be changed to
org.xmlunit.assertj3
.
You can compare any kind of Objects with each other which can be used as a XML sources.
See: Providing Input To XMLUnit - Input.from(Object)
CompareAssert provides assertions for checking if test- and control-XML are identical, similar, not identical or not similar.
The difference between identical and similar is decided by the default DifferenceEvaluator unless you override it.
If the assertion fails a org.junit.ComparisonFailure
will be thrown
by xmlunit-assertj
and a org.opentest4j.AssertionFailedError
by xmlunit-assertj3
.
Throwing special exceptions allows IDEs such as Eclipse, NetBeans and IntelliJ to show a nice DIFF-View for a currently comparing values.
final String control = "<a><b attr=\"abc\"></b></a>";
final String test = "<a><b attr=\"xyz\"></b></a>";
XmlAssert.assertThat(test).and(control).areIdentical();
XmlAssert.assertThat(test).and(control).areNotIdentical();
XmlAssert.assertThat(test).and(control).areSimilar();
XmlAssert.assertThat(test).and(control).areNotSimilar();
The assert class can be configured via a fluent API:
assertThat(test).and(control) // CompareAssert type
.ignoreComments() // [1]
.ignoreCommentsUsingXSLTVersion(xsltVersion) // [2]
.ignoreWhitespace() // [3]
.ignoreElementContentWhitespace() // [4]
.ignoreChildNodesOrder() // [5]
.normalizeWhitespace() // [6]
.withComparisonController(comparisonController) // [7]
.withComparisonFormatter(comparisonFormatter) // [8]
.withComparisonListeners(comparisonListeners) // [9]
.withDifferenceEvaluator(differenceEvaluator) // [10]
.withDifferenceListeners(comparisonListeners) // [11]
.withNodeMatcher(nodeMatcher) // [12]
.withAttributeFilter(attributeFilter) // [13]
.withNodeFilter(nodeFilter) // [14]
.withDocumentBuilderFactory(dbf) // [15]
.withNamespaceContext(prefix2Uri) // [16]
.areSimilar();
-
ignoreComments()
Strips all comments from the test- and control-XML before comparing. It use XSLT 2.0 under the hood. -
ignoreCommentsUsingXSLTVersion()
Strips all comments using given XSLT version from the test- and control-XML before comparing. -
ignoreWhitespace()
Removes all empty text nodes and trim the non-empty ones from the test- and control-XML before comparing. If all you need is to remove text nodes solely consisting of whitespace, then you want to useignoreElementContentWhitespace
. -
ignoreElementContentWhitespace()
Removes all text nodes solely consisting of whitespace (AKA as element content whitespace) before comparing. -
ignoreChildNodesOrder()
Positions of test and control nodes with same name and nested text are always marked as equal (even if they are not). This override NodeMatcher and DifferenceEvaluator. -
normalizeWhitespace()
Removes all empty text nodes and normalize the non-empty ones from the test- and control-XML before comparing. With "normalized" in this context means all whitespace characters are replaced by space characters and consecutive whitespace characters are collapsed. -
withComparisonController()
Use a custom ComparisonController implementation. -
withComparisonFormatter()
Use a custom Formatter for the Error Messages.
See ComparisonFormatter. -
withComparisonListeners()
Registers a listener that is notified of each comparison.
See ComparisonListener. -
withDifferenceEvaluator()
Provide your own custom DifferenceEvaluator implementation.
This may interfere withignoreChildNodesOrder
.
See DifferenceEvaluator. -
withDifferenceListeners()
Registers a listener that is notified of each comparison with outcome other thanComparisonResult.EQUAL
.
See ComparisonListener. -
withNodeMatcher()
Sets the strategy for selecting nodes to compare.
See NodeMatcher. -
withAttributeFilter()
Optional strategy that allows certain attributes to be ignore completely. See AttributeFilter. -
withNodeFilter()
Optional strategy that allows certain nodes to be ignore completely. This may interfere withignoreChildNodesOrder
.
See NodeFilter. -
withDocumentBuilderFactory()
Use the givenDocumentBuilderFactory
when creating a document from the test or control source. -
withNamespaceContext()
Set prefix to URI mapping.
See NamespaceContext.
This example will throw an AssertionError
: "Expected attribute value 'abc' but was 'xyz'".
String testXml = "<a><b attr=\"xyz\"></b></a>";
String controlXml = "<a><b attr=\"abc\"></b></a>";
assertThat(testXml).and(controlXml).areIdentical();
Following example will throw an AssertionError
: "Expected element tag name 'b' but was 'c'".
String testXml = "<a><c/><b/></a>";
String controlXml = "<a><b/><c/></a>";
assertThat(testXml).and(controlXml).areIdentical();
Following assertion will pass:
String testXml = "<a><!-- test --></a>";
String controlXml = "<a></a>";
assertThat(testXml).and(controlXml)
.ignoreComments()
.areIdentical();
Following example will throw an AssertionError
: "Expecting: < control instance > and < test instance > to be not identical".
String testXml = "<Element attr1=\"12\" attr2=\"xy\"/>";
String controlXml = "<Element attr1=\"12\" attr2=\"xy\"/>";
assertThat(testXml).and(controlXml).areNotIdentical();
Check number of differences:
DifferenceComparisonListener differenceListener = new DifferenceComparisonListener();
String testXml = "<Element attr1=\"12\" attr2=\"xyz\"/>";
String controlXml = "<Element attr1=\"122\" attr2=\"xy\"/>";
assertThat(testXml).and(controlXml)
.withDifferenceListeners(differenceListener)
.withComparisonController(ComparisonControllers.Default)
.areNotIdentical();
assertThat(differenceListener.difference).isEqualTo(2);
// ...
private final class DifferenceComparisonListener implements ComparisonListener {
private int difference;
@Override
public void comparisonPerformed(Comparison comparison, ComparisonResult outcome) {
switch (outcome) {
case DIFFERENT:
difference++;
break;
}
}
}
Those XMLs should be similar:
String testXml = "<!DOCTYPE a>" +
"<a>" +
" <c><d/><e/></c>" +
" <b>text</b>" +
"</a>";
String controlXml = "" +
"<a>" +
" <b><![CDATA[text]]></b>" +
" <c><e/><d/></c>" +
"</a>";
assertThat(testXml).and(controlXml)
.ignoreChildNodesOrder()
.areSimilar();
Those XMLs should be similar even if attributes values are different:
String testXml = "<a><b attr=\"abc\"></b></a>";
String controlXml = "<a><b attr=\"xyz\"></b></a>";
assertThat(testXml).and(controlXml)
.withDifferenceEvaluator(
chain(DifferenceEvaluators.Default,
new IgnoreAttributeValueEvaluator("attr")))
.areSimilar();
//...
private final class IgnoreAttributeValueEvaluator implements DifferenceEvaluator {
private final String attributeName;
public IgnoreAttributeValueEvaluator(String attributeName) {
this.attributeName = attributeName;
}
@Override
public ComparisonResult evaluate(Comparison comparison, ComparisonResult outcome) {
final Node controlNode = comparison.getControlDetails().getTarget();
if (comparison.getType() == ATTR_VALUE && controlNode instanceof Attr) {
Attr attr = (Attr) controlNode;
if (attr.getName().equals(attributeName)) {
return ComparisonResult.SIMILAR;
}
}
return outcome;
}
}
Those XMLs should not be similar:
String testXml = "<a><c/><b/></a>";
String controlXml = "<a><b/><c/></a>";
assertThat(testXml).and(controlXml).areNotSimilar();