2

I am using the XMLUnit in JUnit to compare the results of tests. I have a problem wherein there is an Element in my XML which gets the CURRENT TIMESTAMP as the tests run and when compared with the expected output, the results will never match.

To overcome this, I read about using org.xmlunit.diff.NodeFilters, but do not have any examples on how to implement this. The code snippet I have is as below,

final org.xmlunit.diff.Diff documentDiff = DiffBuilder
        .compare(sourcExp)                  
        .withTest(sourceActual)
        .ignoreComments()
        .ignoreWhitespace()                 
        //.withNodeFilter(Node.ELEMENT_NODE)
        .build();
    
return documentDiff.hasDifferences();

My problem is, how do I implement the NodeFilter? What parameter should be passed and should that be passed? There are no samples on this. The NodeFilter method gets Predicate<Node> as the IN parameter. What does Predicate<Node> mean?

Sam
  • 492
  • 2
  • 13
Kashyap Guru
  • 21
  • 1
  • 3

2 Answers2

3

Predicate is a functional interface with a single test method that - in the case of NodeFilter receives a DOM Node as argument and returns a boolean. javadoc of Predicate

An implementation of Predicate<Node> can be used to filter nodes for the difference engine and only those Nodes for which the Predicate returns true will be compared. javadoc of setNodeFilter, User-Guide

Assuming your element containing the timestamp was called timestamp you'd use something like

.withNodeFilter(new Predicate<Node>() {
    @Override
    public boolean test(Node n) {
        return !(n instanceof Element &&
            "timestamp".equals(Nodes.getQName(n).getLocalPart()));
    }
})

or using lambdas

.withNodeFilter(n -> !(n instanceof Element &&
    "timestamp".equals(Nodes.getQName(n).getLocalPart())))

This uses XMLUnit's org.xmlunit.util.Nodes to get the element name more easily.

Stefan Bodewig
  • 3,260
  • 15
  • 22
  • Tried the above method (first one), but it always takes only the Root element and does not work as expected. Even though I give the element name in "", it always takes only the Root element. Am I missing something? – Kashyap Guru Jul 22 '16 at 13:54
  • Sorry, got the logic backwards. You want to return `false` for the `timestamp` nodes as you want to ignore it. I'll edit the answer. – Stefan Bodewig Jul 22 '16 at 14:58
0

The below code worked for me,

public final class IgnoreNamedElementsDifferenceListener implements
    DifferenceListener {

private Set<String> blackList = new HashSet<String>();

public IgnoreNamedElementsDifferenceListener(String... elementNames) {
    for (String name : elementNames) {
        blackList.add(name);
    }
}

public int differenceFound(Difference difference) {
    if (difference.getId() == DifferenceConstants.TEXT_VALUE_ID) {
        if (blackList.contains(difference.getControlNodeDetail().getNode()
                .getParentNode().getNodeName())) {
            return DifferenceListener.RETURN_IGNORE_DIFFERENCE_NODES_IDENTICAL;
        }
    }

    return DifferenceListener.RETURN_ACCEPT_DIFFERENCE;
}

public void skippedComparison(Node node, Node node1) {

}
Kashyap Guru
  • 21
  • 1
  • 3