Пример работы с XMLUnit (вольный перевод). Часть 1.

Написано 28 Апрель, 2013 в категории Java,Разработка ПО

Это Open Source проект, его официальный сайт тут.
XMLUnit позволяет сравнивать XML документы. Достаточно удобно использовать его совместно с JUnit.

Итак, как нам сравнить 2 XML документа? Будем сравнивать 2 документа reference.xml и comparison.xml. Изначально, они будут иметь одинаковую структуру.

Структура файлов reference.xml и comparison.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8"?>
<books>
    <book>
        <name>Angels &amp; Demons</name>
        <isbn>9971-5-0210-0</isbn>
        <author>Dan Brown</author>
        <category></category>
    </book>
    <book>
        <name>You can win</name>
        <isbn>9971-5-0222-0</isbn>
        <author>Shiv Khera</author>
    </book>
</books>

Так будем сравнивать XML-документы:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package com.xmlunit.tutorial.comparison;
 
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.util.List;
 
import org.custommonkey.xmlunit.DetailedDiff;
import org.custommonkey.xmlunit.Diff;
import org.custommonkey.xmlunit.Difference;
import org.xml.sax.SAXException;
 
public class ComparisonTest {
 
    public static void main(String[] args) {
        URL url1 = ComparisonTest.class.getResource("reference.xml");
        URL url2 = ComparisonTest.class.getResource("comparison.xml");
        FileReader fr1 = null;
        FileReader fr2 = null;
        try {
            fr1 = new FileReader(url1.getPath());
            fr2 = new FileReader(url2.getPath());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
 
        try {
            Diff diff = new Diff(fr1, fr2);
            System.out.println("Similar? " + diff.similar());
            System.out.println("Identical? " + diff.identical());
 
            DetailedDiff detDiff = new DetailedDiff(diff);
            List differences = detDiff.getAllDifferences();
            for (Object object : differences) {
                Difference difference = (Difference)object;
                System.out.println("***********************");
                System.out.println(difference);
                System.out.println("***********************");
            }
 
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

Для выявления различий между двумя XML документами достаточно класса Diff. Для получения детальной информации можно использовать класс DetailedDiff. Как это сделать - проиллюстрировано в нашем тестовом классе ComparisonTest.

1. Два документа идентичны.
Запустим тестовый класс для двух абсолютно одинаковых документов.
Получим результат:

Similar? true
Identical? true

Два документа являются полностью идентичными.

2. Сравнение 2 форм пустого элемента.
Попробуем в одном из документов изменить элемент

<category></category>

на его более короткий аналог:

<category/>

Результат:

Similar? true
Identical? true

Т.е. XMLUnit умеет определять разные формы пустого элемента.

3. Чем отличаются "идентичные" элементы от "подобных"?
Чтобы понять чем отличаются "идентичные" документы от "подобных" изменим изначальный вид документа reference.xml. Поменяем местами 2 xml-элемента:
вместо

<author>Dan Brown</author>
<category></category>

сделаем так

<category></category>
<author>Dan Brown</author>

Результат:

Similar? true
Identical? false
***********************
Expected sequence of child nodes '5' but was '7' - comparing  at /books[1]/book[1]/author[1] to  at /books[1]/book[1]/author[1]
***********************
***********************
Expected sequence of child nodes '7' but was '5' - comparing  at /books[1]/book[1]/category[1] to  at /books[1]/book[1]/category[1]
***********************

Проанализировав 2 документа XMLUnit определил, что они подобны по структуре, но из-за разного положения элементов author и category не идентичны! IMHO, сообщение о различиях в структуре довольно невразумительное.

4. А что если в один из документов добавить новый элемент?
Сделаем еще одно изменение в документе comparison.xml
Т.е. теперь comparison.xml

<?xml version="1.0" encoding="UTF-8"?>
<books>
    <book>
        <name>Angels &amp; Demons</name>
        <isbn>9971-5-0210-0</isbn>
        <author>Dan Brown</author>
        <category></category>
    </book>
    <book>
        <name>You can win</name>
        <isbn>9971-5-0222-0</isbn>
        <author>Shiv Khera</author>
    </book>
</books>

А reference.xml

<?xml version="1.0" encoding="UTF-8"?>
<books>
    <book>
        <name>Angels &amp; Demons</name>
        <isbn>9971-5-0210-0</isbn>
        <author>Dan Brown</author>
        <category/>
        <nationality>American</nationality>
    </book>
    <book>
        <name>You can win</name>
        <isbn>9971-5-0222-0</isbn>
        <author>Shiv Khera</author>
    </book>
</books>

т.е. добавился элемент nationality.

А вот каков результат сравнения этих двух документов:

Similar? false
Identical? false
***********************
Expected number of child nodes '9' but was '11' - comparing <book...> at /books[1]/book[1] to <book...> at /books[1]/book[1]
***********************
***********************
Expected text value '
    ' but was '
        ' - comparing <book ...>
    </book> at /books[1]/book[1]/text()[5] to <book ...>
        </book> at /books[1]/book[1]/text()[5]
***********************
***********************
Expected presence of child node 'null' but was 'nationality' - comparing  at null to <nationality...> at /books[1]/book[1]/nationality[1]
***********************
***********************
Expected presence of child node 'null' but was '#text' - comparing  at null to <book ...>
    </book> at /books[1]/book[1]/text()[6]
***********************

XMLUnit сообщает нам о том, что встретился неожиданный xml-элемент, который присутствует в одном документе и отсутствует в другом.

Частичный перевод статьи XML comparison tutorial using XMLUnit