Skip to content
Stefan Bodewig edited this page Nov 15, 2020 · 3 revisions

AssertJ CompareAssert

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)

Assertions

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();

Configuration

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();
  1. ignoreComments()
    Strips all comments from the test- and control-XML before comparing. It use XSLT 2.0 under the hood.
  2. ignoreCommentsUsingXSLTVersion()
    Strips all comments using given XSLT version from the test- and control-XML before comparing.
  3. 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 use ignoreElementContentWhitespace.
  4. ignoreElementContentWhitespace()
    Removes all text nodes solely consisting of whitespace (AKA as element content whitespace) before comparing.
  5. 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.
  6. 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.
  7. withComparisonController()
    Use a custom ComparisonController implementation.
  8. withComparisonFormatter()
    Use a custom Formatter for the Error Messages.
    See ComparisonFormatter.
  9. withComparisonListeners()
    Registers a listener that is notified of each comparison.
    See ComparisonListener.
  10. withDifferenceEvaluator()
    Provide your own custom DifferenceEvaluator implementation.
    This may interfere with ignoreChildNodesOrder.
    See DifferenceEvaluator.
  11. withDifferenceListeners()
    Registers a listener that is notified of each comparison with outcome other than ComparisonResult.EQUAL.
    See ComparisonListener.
  12. withNodeMatcher()
    Sets the strategy for selecting nodes to compare.
    See NodeMatcher.
  13. withAttributeFilter()
    Optional strategy that allows certain attributes to be ignore completely. See AttributeFilter.
  14. withNodeFilter()
    Optional strategy that allows certain nodes to be ignore completely. This may interfere with ignoreChildNodesOrder.
    See NodeFilter.
  15. withDocumentBuilderFactory()
    Use the given DocumentBuilderFactory when creating a document from the test or control source.
  16. withNamespaceContext()
    Set prefix to URI mapping.
    See NamespaceContext.

Examples

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();