-
Notifications
You must be signed in to change notification settings - Fork 8
DifferenceEvaluator
A DifferenceEvaluator
decides about the outcome of a comparison. A
couple of convenience implementations have been collected in the
DifferenceEvaluators
class.
DifferenceEvaluators.Default
uses rules very similar to those of
XMLUnit for Java 1.x in order to decide whether a technically
different outcome is ComparisonResult.DIFFERENT
or rather a not so
critical difference that would still allow the pieces of XML to be
considered SIMILAR
.
With the default evaluator the following differences are handled as similar:
- CDATA and Text nodes with the same content
- DOCTYPE differences
- different
xsi:noNamspaceSchemaLocation
andxsi:noNamspaceSchemaLocation
- different XML namespaces prefixes
- explicit/implicit status of attributes.
- a different order of child nodes
- XML encoding
If you use your own DifferenceEvaluator
implementation you can
combine it with the default DifferenceEvaluator.
❗ This Example implementations are strongly simplified without exception handling or not-null checks. They should only be a clue what a DifferenceEvaluator can do. ❗
In some cases you want ignore some special differences of an XML content. Typical cases are elements/attributes which are filled with random values like UUIDs or current date/time information.
class IgnoreAttributeDifferenceEvaluator implements DifferenceEvaluator {
private String attributeName;
public IgnoreAttributeDifferenceEvaluator(String attributeName) {
this.attributeName = attributeName;
}
@Override
public ComparisonResult evaluate(Comparison comparison, ComparisonResult outcome) {
if (outcome == ComparisonResult.EQUAL) return outcome; // only evaluate differences.
final Node controlNode = comparison.getControlDetails().getTarget();
if (controlNode instanceof Attr) {
Attr attr = (Attr) controlNode;
if (attr.getName().equals(attributeName)) {
return ComparisonResult.SIMILAR; // will evaluate this difference as similar
}
}
return outcome;
}
}
Usage:
final String control = "<a><b attr=\"abc\"></b></a>";
final String test = "<a><b attr=\"xyz\"></b></a>";
Diff myDiff = DiffBuilder.compare(control).withTest(test)
.withDifferenceEvaluator(new IgnoreAttributeDifferenceEvaluator("attr"))
.checkForSimilar()
.build();
Assert.assertFalse(myDiff.toString(), myDiff.hasDifferences());
for Java or for .NET:
public class IgnoreAttributeDifferenceEvaluator {
private string attributeName;
public IgnoreAttributeDifferenceEvaluator(string attributeName) {
this.attributeName = attributeName;
}
public ComparisonResult Evaluate(Comparison comparison, ComparisonResult outcome) {
if (outcome == ComparisonResult.EQUAL) return outcome; // only evaluate differences.
XmlNode controlNode = comparison.ControlDetails.Target;
XmlAttribute attr = controlNode as XmlAttribute;
if (attr != null) {
if (attr.Name == attributeName) {
return ComparisonResult.SIMILAR; // will evaluate this difference as similar
}
}
return outcome;
}
}
usage
string control = "<a><b attr=\"abc\"></b></a>";
string test = "<a><b attr=\"xyz\"></b></a>";
var myDiff = DiffBuilder.Compare(control).WithTest(test)
.WithDifferenceEvaluator(new IgnoreAttributeDifferenceEvaluator("attr").Evaluate)
.CheckForSimilar()
.Build();
Assert.IsFalse(myDiff.HasDifferences(), myDiff.ToString());
In some cases you don't want compare the content of an element as String.
This example shows how to compare a special element with BigDecimal.
Because for our fictive business case it doesn't mater if the value is "1.0" or "1.00".
class BigDecimalElementDifferenceEvaluator implements DifferenceEvaluator {
private String elementName;
public BigDecimalElementDifferenceEvaluator(String elementName) {
this.elementName = elementName;
}
@Override
public ComparisonResult evaluate(Comparison comparison, ComparisonResult outcome) {
if (outcome == ComparisonResult.EQUAL) return outcome; // only evaluate differences.
final Node controlNode = comparison.getControlDetails().getTarget();
final Node testNode = comparison.getTestDetails().getTarget();
if (controlNode.getParentNode() instanceof Element && testNode.getParentNode() instanceof Element) {
Element controlElement = (Element) controlNode.getParentNode();
Element testElement = (Element) testNode.getParentNode();
if (controlElement.getNodeName().equals(elementName)) {
final String controlValue = controlElement.getTextContent();
final String testValue = testElement.getTextContent();
if (new BigDecimal(controlValue).compareTo(new BigDecimal(testValue)) == 0) {
return ComparisonResult.SIMILAR;
}
}
}
return outcome;
}
}
Usage:
final String control = "<a><amount>1</amount></a>";
final String test = "<a><amount>1.0000</amount></a>";
Diff myDiff = DiffBuilder.compare(control).withTest(test)
.withDifferenceEvaluator(new BigDecimalElementDifferenceEvaluator("amount"))
.checkForSimilar()
.build();
Assert.assertFalse(myDiff.toString(), myDiff.hasDifferences());
If you want use your own DifferenceEvaluator implementation in combination with the default DifferenceEvaluator you must combine them:
Diff myDiff = DiffBuilder.compare(control).withTest(test)
.withDifferenceEvaluator(
DifferenceEvaluators.chain(DifferenceEvaluators.Default,
new MyCustomDifferenceEvaluator()))
.checkForSimilar()
.build();
There are two helper methods to combine DifferenceEvaluators:
-
DifferenceEvaluators.first(...)
Combines multiple DifferenceEvaluators so that the first one that changes the outcome wins. -
DifferenceEvaluators.chain(...)
Combines multiple DifferenceEvaluators so that the result of the first Evaluator will be passed to the next Evaluator.
- Overview
- General Concepts
- Comparing XML
- Validating XML
- Utilities
- Migrating from XMLUnit 1.x to 2.x
- Known Issues