Open In App

How to Test a Maven Project using XMLUnit2?

Last Updated : 22 Dec, 2022
Improve
Improve
Like Article
Like
Save
Share
Report

XML stands for Extensible Markup Language and it is widely used in many places for software projects. Whenever we need to port information across multiple operating systems/multiple languages, XML is an effective way of communication. To convey messages easily also, XML helps and it should be well-formed and well-structured. Then only a mode of communication will be appropriate. In this tutorial, let us see how XML details are validated by using XMLUnit 2.x. XMLUnit 2.x helps us to test and verify the XML contents. Via a Maven sample project, let us see the concepts.

Example Maven Project

Required Maven Dependency to use XMLUnit 2.x

<dependency>
    <groupId>org.xmlunit</groupId>
    <artifactId>xmlunit-core</artifactId>
    <version>2.2.1</version>
</dependency>
<dependency>
    <groupId>org.xmlunit</groupId>
    <artifactId>xmlunit-matchers</artifactId>
    <version>2.2.1</version>
</dependency>

Let us create a sample project containing a few valid well-structured XML for testing against XMLUnit 2.x

 

As it is a maven project, let us see

pom.xml

XML




<?xml version="1.0" encoding="UTF-8"?>
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                        http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <artifactId>gfg_xmlunit-2_sample</artifactId>
    <name>gfg_xmlunit-2_sample</name>
 
    <parent>
        <groupId>com.gfg</groupId>
        <artifactId>testing-modules</artifactId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>
 
    <dependencies>
        <dependency>
            <groupId>org.xmlunit</groupId>
            <artifactId>xmlunit-matchers</artifactId>
            <version>${xmlunit.version}</version>
        </dependency>
        <dependency>
            <groupId>org.xmlunit</groupId>
            <artifactId>xmlunit-core</artifactId>
            <version>${xmlunit.version}</version>
        </dependency>
    </dependencies>
 
    <properties>
        <!-- testing -->
        <xmlunit.version>2.3.0</xmlunit.version>
    </properties>
 
</project>


Important files that are required for checking and differentiating against attributes

IgnoringAttributeDifferenceEvaluator.java

Java




import org.w3c.dom.Attr;
import org.w3c.dom.Node;
import org.xmlunit.diff.Comparison;
import org.xmlunit.diff.ComparisonResult;
import org.xmlunit.diff.DifferenceEvaluator;
 
public class IgnoringAttributeDifferenceEvaluator implements DifferenceEvaluator {
 
    private String attributeName;
 
    public IgnoringAttributeDifferenceEvaluator(String attributeName) {
        this.attributeName = attributeName;
    }
 
    @Override
    public ComparisonResult evaluate(Comparison comparison, ComparisonResult result) {
        if (result == ComparisonResult.EQUAL)
            return result;
        final Node controlNode = comparison.getControlDetails().getTarget();
        if (controlNode instanceof Attr) {
            Attr attr = (Attr) controlNode;
            if (attr.getName().equals(attributeName)) {
                return ComparisonResult.SIMILAR;
            }
        }
        return result;
    }
}


Let us start to test the XML one by one.

validatingForIdentityAmong2XMLs: Only valid XML needs to be taken and if the content and sequence in the documents are exactly the same, then the below test will be successful. We have taken a sample XML and tested XML and as both content and sequence are matching, they are identical and provide a positive result.

Java




@Test
public void validatingForIdentityAmong2XMLs()
{
    String givenXml
        = "<struct><int>30</int><boolean>true</boolean></struct>";
    String testXml
        = "<struct><int>30</int><boolean>true</boolean></struct>";
    assertThat(testXml, isIdenticalTo(givenXml));
}


In case if there are differences are seen in the given 2 XMLs, they are detected by Difference Engine. Usually, if XML is not identical, the comparison process stops in the first difference itself. If we want to get all differences, along with the asserts, we can print them and get as given below.

Java




@Test
public void generationOfDifferencesAmong2XMLs()
    throws Exception
{
    String givenXml
        = "<struct><int>30</int><boolean>true</boolean></struct>";
    String testXml
        = "<struct><boolean>true</boolean><int>30</int></struct>";
    Diff myDiff = DiffBuilder.compare(givenXml)
                      .withTest(testXml)
                      .build();
    Iterator<Difference> iter
        = myDiff.getDifferences().iterator();
    int size = 0;
    while (iter.hasNext()) {
        System.out.println(iter.next().toString());
        size++;
    }
    assertThat(size, greaterThan(1));
}


 

We can compare XML from a given source file. Given XML may contain different tags and hence instead of specifying it as a test string let us get it from the file.

test,xml contents

XML




<struct>
    <int>300</int>
    <boolean>true</boolean>
</struct>


control.xml contents

XML




<struct>
    <int>300</int>
    <boolean>true</boolean>
</struct>


Checking for XML contents present in 2 XMLs

Java




@Test
public void validateViaAFileSource()
{
    ClassLoader sampleClassLoader
        = getClass().getClassLoader();
    String testFilePath
        = sampleClassLoader.getResource("test.xml")
              .getPath();
    String controlFilePath
        = sampleClassLoader.getResource("control.xml")
              .getPath();
    assertThat(
        Input.fromFile(testFilePath),
        isSimilarTo(Input.fromFile(controlFilePath)));
}


Validation:

Using the Validator class, XML validation is done by XML Unit 2.x. Validator class can be created by using

Validator validator = Validator.forLanguage(Languages.W3C_XML_SCHEMA_NS_URI);

Let us see the same by taking one XSD and one XML file

student.xsd

XML




<?xml version = "1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name='class'>
        <xs:complexType>
            <xs:sequence>
                <xs:element name='student' type='StudentObject'
                    minOccurs='0' maxOccurs='unbounded' />
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:complexType name="StudentObject">
        <xs:sequence>
            <xs:element name="name" type="xs:string" />
            <xs:element name="age" type="xs:positiveInteger" />
        </xs:sequence>
        <xs:attribute name='id' type='xs:positiveInteger' />
    </xs:complexType>
</xs:schema>


student_with_error.xml (Values are present here but with errors)

XML




<?xml version = "1.0"?>
<class>
    <student id="1000">
        <name>Rachel</name>
        <age>30</age>
    </student>
 
        <student id="1001">
            <name>Ross</name>
            <age>30</age>
        </student>
</class>


student.xml  (Valid xml)

XML




<?xml version = "1.0"?>
<class>
    <student id="393">
        <name>Rachel</name>
        <age>30</age>
    </student>
    <student id="493">
        <name>Ross</name>
        <age>30</age>
    </student>
</class>


By using Validator, the below steps are carried out

Java




@Test
public void validatingWrongXml_AndFailsAgainstXsd_thenCorrect() {
        Validator validator = Validator.forLanguage(Languages.W3C_XML_SCHEMA_NS_URI);
        validator.setSchemaSource(Input.fromStream(SampleXMLUnitTest.class.getResourceAsStream("/student.xsd")).build());
        ValidationResult r = validator.validateInstance(Input.fromStream(SampleXMLUnitTest.class.getResourceAsStream("/student_with_error.xml")).build());
        assertFalse(r.isValid());
    }
 
@Test
public void validatingCorrectXml_whenValidatesAgainstXsd_thenCorrect() {
        Validator validator = Validator.forLanguage(Languages.W3C_XML_SCHEMA_NS_URI);
        validator.setSchemaSource(Input.fromStream(SampleXMLUnitTest.class.getResourceAsStream("/student.xsd")).build());
        ValidationResult validationResult = validator.validateInstance(Input.fromStream(SampleXMLUnitTest.class.getResourceAsStream("/student.xml")).build());
        Iterator<ValidationProblem> problems = validationResult.getProblems().iterator();
        while (problems.hasNext()) {
            System.out.println(problems.next().toString());
        }
        assertTrue(validationResult.isValid());
    }


XPath can be checked by using the below way

Java




@Test
public void validateExistingXPath() {
        ClassLoader sampleClassLoader = getClass().getClassLoader();
        assertThat(Input.fromFile(new File(sampleClassLoader.getResource("teachers.xml").getFile())), hasXPath("//teachers"));
        assertThat(Input.fromFile(new File(sampleClassLoader.getResource("teachers.xml").getFile())), hasXPath("//teacher"));
        assertThat(Input.fromFile(new File(sampleClassLoader.getResource("teachers.xml").getFile())), hasXPath("//subject"));
        assertThat(Input.fromFile(new File(sampleClassLoader.getResource("teachers.xml").getFile())), hasXPath("//@department"));
    }


The complete code for the above test cases is available here

Java




import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.greaterThan;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.xmlunit.matchers.CompareMatcher.isIdenticalTo;
import static org.xmlunit.matchers.CompareMatcher.isSimilarTo;
import static org.xmlunit.matchers.HasXPathMatcher.hasXPath;
 
import java.io.File;
import java.util.Iterator;
 
import org.junit.Test;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.xmlunit.builder.DiffBuilder;
import org.xmlunit.builder.Input;
import org.xmlunit.diff.Diff;
import org.xmlunit.diff.Difference;
import org.xmlunit.validation.Languages;
import org.xmlunit.validation.ValidationProblem;
import org.xmlunit.validation.ValidationResult;
import org.xmlunit.validation.Validator;
import org.xmlunit.xpath.JAXPXPathEngine;
 
public class SampleXMLUnitTest {
   
    @Test
    public void validatingWrongXml_AndFailsAgainstXsd_thenCorrect() {
        Validator validator = Validator.forLanguage(Languages.W3C_XML_SCHEMA_NS_URI);
        validator.setSchemaSource(Input.fromStream(SampleXMLUnitTest.class.getResourceAsStream("/students.xsd")).build());
        ValidationResult r = validator.validateInstance(Input.fromStream(SampleXMLUnitTest.class.getResourceAsStream("/students_with_error.xml")).build());
        assertFalse(r.isValid());
    }
 
    @Test
    public void validatingCorrectXml_whenValidatesAgainstXsd_thenCorrect() {
        Validator validator = Validator.forLanguage(Languages.W3C_XML_SCHEMA_NS_URI);
        validator.setSchemaSource(Input.fromStream(SampleXMLUnitTest.class.getResourceAsStream("/students.xsd")).build());
        ValidationResult validationResult = validator.validateInstance(Input.fromStream(SampleXMLUnitTest.class.getResourceAsStream("/students.xml")).build());
        Iterator<ValidationProblem> problems = validationResult.getProblems().iterator();
        while (problems.hasNext()) {
            System.out.println(problems.next().toString());
        }
        assertTrue(validationResult.isValid());
    }
 
    @Test
    public void validateXPath_AndRetrieveNodes() {
        ClassLoader classLoader = getClass().getClassLoader();
 
        Iterable<Node> i = new JAXPXPathEngine().selectNodes("//teacher", Input.fromFile(new File(classLoader.getResource("teachers.xml").getFile())).build());
        assertNotNull(i);
        int count = 0;
        for (Iterator<Node> iterator = i.iterator(); iterator.hasNext();) {
            count++;
            Node node = iterator.next();
            assertEquals("teacher", node.getNodeName());
            NamedNodeMap namedNodeMap = node.getAttributes();
            assertEquals("department", namedNodeMap.item(0).getNodeName());
            assertEquals("id", namedNodeMap.item(1).getNodeName());
            assertEquals("teacher", node.getNodeName());
        }
        assertEquals(2, count);
    }
 
    @Test
    public void validateExistingXPath() {
        ClassLoader sampleClassLoader = getClass().getClassLoader();
        assertThat(Input.fromFile(new File(sampleClassLoader.getResource("teachers.xml").getFile())), hasXPath("//teachers"));
        assertThat(Input.fromFile(new File(sampleClassLoader.getResource("teachers.xml").getFile())), hasXPath("//teacher"));
        assertThat(Input.fromFile(new File(sampleClassLoader.getResource("teachers.xml").getFile())), hasXPath("//subject"));
        assertThat(Input.fromFile(new File(sampleClassLoader.getResource("teachers.xml").getFile())), hasXPath("//@department"));
    }   
 
    @Test
    public void validateViaAFileSource() {
        ClassLoader sampleClassLoader = getClass().getClassLoader();
        String testFilePath = sampleClassLoader.getResource("test.xml").getPath();
        String controlFilePath = sampleClassLoader.getResource("control.xml").getPath();
        assertThat(Input.fromFile(testFilePath), isSimilarTo(Input.fromFile(controlFilePath)));
    }
 
    @Test
    public void validatingForIdentityAmong2XMLs() {
        String givenXml = "<struct><int>30</int><boolean>true</boolean></struct>";
        String testXml = "<struct><int>30</int><boolean>true</boolean></struct>";
        assertThat(testXml, isIdenticalTo(givenXml));
    }
 
    @Test
    public void generationOfDifferencesAmong2XMLs() throws Exception {
        String givenXml = "<struct><int>30</int><boolean>true</boolean></struct>";
        String testXml = "<struct><boolean>true</boolean><int>30</int></struct>";
        Diff myDiff = DiffBuilder.compare(givenXml).withTest(testXml).build();
        Iterator<Difference> iter = myDiff.getDifferences().iterator();
        int size = 0;
        while (iter.hasNext()) {
            System.out.println(iter.next().toString());
            size++;
        }
        assertThat(size, greaterThan(1));
    
 
}


Output on running the test file

 

Conclusion

XML is widely used throughout software projects. There will be a need to test the XML for its validity. Upon confirming the validity, XML can be ported to the required locations. For that XMLUnit 2.x library is very helpful and in the above article, we have seen with few scenarios.



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads