Suppose I have two xml strings
<test> <elem>a</elem> <elem>b</elem> </test> <test> <elem>b</elem> <elem>a</elem> </test>
How to write a test that compares those two strings and ignores the element order?
I want the test to be as short as possible, no place for 10-line XML parsing etc. I’m looking for a simple assertion or something similar.
I have this (which doesn’t work)
Diff diff = XMLUnit.compareXML(expectedString, actualString); XMLAssert.assertXMLEqual("meh", diff, true);
Advertisement
Answer
My original answer is outdated. If I would have to build it again i would use xmlunit 2 and xmlunit-matchers. Please note that for xml unit a different order is always ‘similar’ not equals.
@Test public void testXmlUnit() { String myControlXML = "<test><elem>a</elem><elem>b</elem></test>"; String expected = "<test><elem>b</elem><elem>a</elem></test>"; assertThat(myControlXML, isSimilarTo(expected) .withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.byNameAndText))); //In case you wan't to ignore whitespaces add ignoreWhitespace().normalizeWhitespace() assertThat(myControlXML, isSimilarTo(expected) .ignoreWhitespace() .normalizeWhitespace() .withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.byNameAndText))); }
If somebody still want’t to use a pure java implementation here it is. This implementation extracts the content from xml and compares the list ignoring order.
public static Document loadXMLFromString(String xml) throws Exception { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); InputSource is = new InputSource(new StringReader(xml)); return builder.parse(is); } @Test public void test() throws Exception { Document doc = loadXMLFromString("<test>n" + " <elem>b</elem>n" + " <elem>a</elem>n" + "</test>"); XPathFactory xPathfactory = XPathFactory.newInstance(); XPath xpath = xPathfactory.newXPath(); XPathExpression expr = xpath.compile("//test//elem"); NodeList all = (NodeList) expr.evaluate(doc, XPathConstants.NODESET); List<String> values = new ArrayList<>(); if (all != null && all.getLength() > 0) { for (int i = 0; i < all.getLength(); i++) { values.add(all.item(i).getTextContent()); } } Set<String> expected = new HashSet<>(Arrays.asList("a", "b")); assertThat("List equality without order", values, containsInAnyOrder(expected.toArray())); }