📜 ⬆️ ⬇️

Proper validation of XML data in java-projects

Hi,% username%.

In a number of projects I needed to compare XML data in tests.

Indeed, it happens that the result of the work of your module is XML data. If so, then how they are generated should be checked in accordance with the principles of TDD . I, in turn, try to stick with them when developing.
')
Under the cut, I will try to tell you how best, in my opinion, is to test the generation of XML in code. I used XmlUnit as an XML comparison tool.


I need to quickly and conveniently compare XML data in tests. I did not want to reinvent the wheel, and I chose the most popular library for this purpose. In the beginning I will try to describe the list of problems that I solved.

How it all started


Once working on another project, I broke a colleague's test. When I began to study the test, I found there something like this:
@Test public void testSomeXmlGeneration() { //      String result = someModule.generateXML(); //     XML  File file = File.createTempFile("actial_data", ".xml"); FileWriter fileWriter = new FileWriter(file); fileWriter.write(result); fileWriter.close(); File fileExpect = new File(this.getClass().getResource("/expected_data.xml").getFile()); FileAssert.assertBinaryEquals(fileExpect, file); } 


This is where data is generated and compared with the original from resources. For tests used JUnit4 . I also note that, ideally, the original file should be written manually by the developer.

What's wrong with this code?

I will try to justify the points.

1. Too many gestures to compare two files.



Indeed, there are a lot of movements, and if you have to compare often, then this code is copied back and forth in one form or another, which is often the case. Something to do with this prevents the lack of time.

2. There is no validation check of the generated XML code.



Due to the fact that validity was not checked, another module refused to process non-valid data, although according to tests everything was fine. I wanted to solve this problem at the test debugging stage.

3. Identical in structure and XML data may be different due to different order of tags or attributes.



For example:
Option 1Change the order of tags
 <?xml version="1.0" encoding="UTF-8"?> <project> <name>some project</name> <description>desc</description> </project> 

 <?xml version="1.0" encoding="UTF-8"?> <project> <description>desc</description> <name>some project</name> </project> 


or so:
Option 2Change the order of attributes
 <?xml version="1.0" encoding="UTF-8"?> <project name=”some project” description=”desc”/> 

 <?xml version="1.0" encoding="UTF-8"?> <project description=”desc” name=”some project”/> 



4. I want XML tests with formatting



In the test presented at the beginning of the article, XML data was presented without spaces or line breaks. Feel the difference:
Option 3Remove spaces and line breaks
 <?xml version="1.0" encoding="UTF-8"?> <project> <name>some project</name> <description>desc</description> </project> 

 <?xml version="1.0" encoding="UTF-8"?> <project><description>desc</description><name>some project</name></project> 



5. Automatically processed transfers within the data.



Option 3Carry lines within data
 <?xml version="1.0" encoding="UTF-8"?> <project> <name>some project</name> <description>desc</description> </project> 

 <?xml version="1.0" encoding="UTF-8"?> <project> <name> some project </name> <description>desc</description> </project> 



In the test considered at the beginning of the article, the source data was in one line, only tags and attributes were somewhat larger. To plant a mistake there is very simple, and correcting it so that the test passes is long and painful.

All the problems described above, I decided to eliminate the coordinate:


After a brief search, my choice fell on XmlUnit .

Basic ways to connect XmlUnit



The XmlUnit library is primarily a JUnit3 extension.
Its basis is the XMLTestCase class, a successor of the TestCase class from JUnit3. Here you can see the main examples of using the class.
In practice, XmlUnit is easy to use in other test libraries. For this there is a class Diff.

So let's go


I use maven for my projects. Let's connect XmlUnit as dependence in maven. To do this, open pom.xml and add a new dependency in dependencies.
 <dependencies> <!-- ….-  ... --> <dependency> <groupId>xmlunit</groupId> <artifactId>xmlunit</artifactId> <version>1.3</version> </dependency> </dependencies> 


We open the test, we write there new comparison

 @Test public void testSomeXmlGeneration() { //      String result = someModule.generateXML(); Diff diff = new Diff(getResourceAsString("/expeced_data.xml"), result); assertTrue("XML   ", diff.similar()); } 


Run the test ... and does not work. A little more searching on the Internet, I found a solution. It was in the spaces between the tags. To ignore them, you need to add a pre-setting:

 @Before public void setUp() throws Exception { XMLUnit.setIgnoreComments(true); XMLUnit.setIgnoreWhitespace(true); } 


It seems to be all, you can enjoy the result. However, suppose we made a mistake in XML. Then we need to know exactly which tag is the problem.
The following example will help us solve it:

 //    class TestXmls { @Before public void setUp() throws Exception { XMLUnit.setIgnoreComments(true); XMLUnit.setIgnoreWhitespace(true); } @Test public void testSomeXmlGeneration() { //      String result = someModule.generateXML(); Diff diff = new Diff(getResourceAsString("/expeced_data.xml"), result); Tools.showXmlDiff(diff); assertTrue("XML   ", diff.similar()); } } //    public final class Tools { public static void showXmlDiff(Diff diff) { 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("***********************"); } } } 


Notice the showXmlDiff method. In it we get a list of differences and display it.

What else can you do good?





Literature



References on which I scooped information.



UPD: According to the results of the discussion with Lure_of_Chaos, I added another link to the list of references. There you can read about the validation of XML and about other beautiful chips, which for some reason are not written in the official documentation.

Once again, I note that XmlUnit allows you to check the validity of XML by DTD and XSD schemes.
As Lure_of_Chaos correctly pointed out , in the XSD schemes, you can require the order in which the elements are specified . Testing this in tests is critical.

UPD2 : corrected the last test example . Thanks, Colwin .
That's all, thank you for your attention.

Source: https://habr.com/ru/post/127473/


All Articles