Assertj-core: Introduce XPath like assertions

Created on 24 Sep 2013  ·  26Comments  ·  Source: assertj/assertj-core

It would quite useful to have XPath like assertions (similar to what it is available in XMLUnit but with a fluent interface of course :-) )

For example:

String mySolarSystemXML = "<solar-system><planet name='Earth' position='3' supportsLife='yes'/><planet name='Venus' position='4'/></solar-system>";

assertXpathExists("//planet[@name='Earth']", mySolarSystemXML);

assertXpathNotExists("//star[@name='alpha centauri']",
                     mySolarSystemXML);

assertXpathsEqual("//planet[@name='Earth']",
                  "//planet[@position='3']", mySolarSystemXML);

assertXpathsNotEqual("//planet[@name='Venus']",
                     "//planet[@supportsLife='yes']",
                     mySolarSystemXML);

[Example from http://xmlunit.sourceforge.net/userguide/html/index.html#Xpath%20Tests ]

Most helpful comment

we've just released XMLUnit 2.6.1 with the new xmlunit-assertj module, see https://github.com/xmlunit/user-guide/wiki/XPath-Support#multiplenodeassert--singlenodeassert

All 26 comments

That would be nice indeed !

Reusing your example:

String xml = "<solar-system>" +
               "<planet name='Earth' position='3' supportsLife='yes'/>" + 
               "<planet name='Venus' position='4'/>" +
             "</solar-system>";

I find theses assertions naming clear:

assertThat(xml).containsXpath("//planet[@name='Earth']");
assertThat(xml).doesNotContainXpath("//planet[@name='alpha centauri']");

but the following ones not so much:

assertThat(xml).xpathEqual("//planet[@name='Earth']", "//planet[@position='3']");
assertThat(xml).xpathNotEqual("//planet[@name='Venus']", "//planet[@supportsLife='yes']");

Any ideas for a better naming ?

maybe:

assertThat(xml).hasEqualXpaths("//planet[@name='Earth']", "//planet[@position='3']");

or:

assertThat(xml).xpaths("//planet[@name='Earth']", "//planet[@position='3']").toBeEqual();

// if we go that way, we may also rewrite containsXpath assertion as 
assertThat(xml).xpath("//planet[@name='Earth']").toExist();

WDYT ?

My examples were based on XMLUnit syntax just to give you the idea.

Implementing from scratch, we can may be use a different approach, staying closer to xpath terminology.

To check if an xpath exists in the xml (same as your containsXpath)

assertThat(xml).hasNode(xpath) 

Some assertions to work on a single node:

assertThat(xml).findNode(xpath1).isSameNodeAs(xpath2)
assertThat(xml).findNode(xpath1).hasValue(value)
assertThat(xml).findNode(xpath1).hasAttribute(attrib)

findNode extracts a single node from the xpath. We could also name it getNode. This because we cannot use a getter as assertThat parameter. xpath1 should return a single node or we assume we use the first node. Assertions fails if xpath1 gives no results.

Using the example

assertThat(xml).findNode("//planet[@name='Earth']").isSameNodeAs("//planet[@position='3']")
assertThat(xml).findNode("//planet[@name='Earth']").hasValue(3);   // false
assertThat(xml).findNode("//planet[@name='Earth']").hasAttribute("supportsLife")

We could also add other checks like isParentOf(xpath2), isChildrenOf(xpath2)...

Similar concept for xpaths returning a set of nodes (not just one).

assertThat(xml).findSet(xpath1).isEmpty();
assertThat(xml).findSet(xpath1).hasSize(3);
...

like standard set assertions

I like the overall approach I'm just a little bit worried that it is not obvious we are using XPath expression unless we check javadoc.

I would rather go for:

assertThat(xml).hasXPathNode(xpath) 

Similarly (using 'finding' instead of 'find' seems better to me):

assertThat(xml).findingNodeByXPath("//planet[@name='Earth']")
                   .isSameNodeAs("//planet[@position='3']")
                   .hasValue(3) // false
                   .hasAttributeKey("supportsLife")
                   .hasAttributeValue("yes")
                   .hasAttribute("supportsLife", "yes")

I agree finding node set could be really useful:

assertThat(xml).findingNodeSetByXPath(xpath1).isEmpty();
assertThat(xml).findingNodeSetByXPath(xpath1).hasSize(3);

Names are longer but less ambiguous, WDYT ?

Great. I think clearness is very important.

I don't have time to help in coding but I can do testing on my real cases. Just let me know when something is available for test.

Gualtiero

Le mail ti raggiungono ovunque con BlackBerry® from Vodafone!

-----Original Message-----
From: Joel Costigliola [email protected]
Date: Sat, 28 Sep 2013 08:01:10
To: joel-costigliola/[email protected]
Reply-To: joel-costigliola/assertj-core [email protected]
Cc: Gualtiero TestaGualtiero.[email protected]
Subject: Re: [assertj-core] Introduce XPath like assertions (#111)

I like the overall approach I'm just a little bit worried that it is not obvious we are using XPath expression unless we check javadoc.

I would rather go for:

assertThat(xml).hasXPathNode(xpath) 

Similarly (using 'finding' instead of 'find' seems better to me):

assertThat(xml).findingNodeByXPath("//planet[@name='Earth']")
                   .isSameNodeAs("//planet[@position='3']")
                   .hasValue(3) // false
                   .hasAttributeKey("supportsLife")
                   .hasAttributeValue("yes")
                   .hasAttribute("supportsLife", "yes")

I agree finding node set could be really useful:

assertThat(xml).findingNodeSetByXPath(xpath1).isEmpty();
assertThat(xml).findingNodeSetByXPath(xpath1).hasSize(3);

Names are longer but less ambiguous, WDYT ?


Reply to this email directly or view it on GitHub:
https://github.com/joel-costigliola/assertj-core/issues/111#issuecomment-25299598

All right.

I'm thinking to introduce these assertions with assertThatXml(xml) intead of assertThat(xml) to avoid cluttering String assertions not related to XML.

Any objections ?

Hello,

assertThat(xml(txt))
Where xml() convert a string to org.jdom.Document ?

Regards,
Clément
Le 12 oct. 2013 23:36, "Joel Costigliola" [email protected] a
écrit :

I'm thinking to introduce these assertions with assertThatXml(xml) intead
of assertThat(xml) to avoid cluttering String assertions not related to
XML.

Any objections ?


Reply to this email directly or view it on GitHubhttps://github.com/joel-costigliola/assertj-core/issues/111#issuecomment-26206554
.

I agree
Le mail ti raggiungono ovunque con BlackBerry® from Vodafone!

-----Original Message-----
From: Joel Costigliola [email protected]
Date: Sat, 12 Oct 2013 14:36:27
To: joel-costigliola/[email protected]
Reply-To: joel-costigliola/assertj-core [email protected]
Cc: Gualtiero TestaGualtiero.[email protected]
Subject: Re: [assertj-core] Introduce XPath like assertions (#111)

I'm thinking to introduce these assertions with assertThatXml(xml) intead of assertThat(xml) to avoid cluttering String assertions not related to XML.

Any objections ?


Reply to this email directly or view it on GitHub:
https://github.com/joel-costigliola/assertj-core/issues/111#issuecomment-26206554

Or it could be something like

assertThat(xml).asXml().anyxmlassertion....

Where asXml is a delegation method in String assertions which jumps to xml dedicated assertions.

In this way you save the assertThat "standard" usage

Gualtiero

Le mail ti raggiungono ovunque con BlackBerry® from Vodafone!

-----Original Message-----
From: "Gualtiero Testa" gualtiero.[email protected]
Date: Sun, 13 Oct 2013 06:54:56
To: joel-costigliola/[email protected]
Reply-To: gualtiero.[email protected]
Subject: R: Re: [assertj-core] Introduce XPath like assertions (#111)

I agree
Le mail ti raggiungono ovunque con BlackBerry® from Vodafone!

-----Original Message-----
From: Joel Costigliola [email protected]
Date: Sat, 12 Oct 2013 14:36:27
To: joel-costigliola/[email protected]
Reply-To: joel-costigliola/assertj-core [email protected]
Cc: Gualtiero TestaGualtiero.[email protected]
Subject: Re: [assertj-core] Introduce XPath like assertions (#111)

I'm thinking to introduce these assertions with assertThatXml(xml) intead of assertThat(xml) to avoid cluttering String assertions not related to XML.

Any objections ?


Reply to this email directly or view it on GitHub:
https://github.com/joel-costigliola/assertj-core/issues/111#issuecomment-26206554

Clément, I prefer Gualtiero's approach because it is more IDE friendly, with assertThat(xml(txt)) approach, you need special IDE configuration to show xml(txt) when invoking code completion.

I'm gonna post the different approached to the mailing list to have other opinions before making my mind.

Thanks guys

Users have chosen : assertThat(xml).asXml() option, so let's go for it.

but we might also implements the other options and let users choose the one they prefer ...

I don't like asXml(). It does not conform to other asserj assertions. I would suggest renaming it to isXml() and making it a regular assertion, so before any xpath assertion we would be forced to check if we have proper xml. Example:

assertThat(xml).isXml().withElement("//planet[@name='Earth']");

The problem wih isXml() is that it's not clear that it will transform given string to an XML document.

As we will probably implement assertThat(xml(txt)) option in addition to assertThat(xml).asXml(), you will have the choice to use whatever option you prefer.

I have already made some research in context of this issue. I hope to submit PR around New Year's Eve.

That's great news :)

@mpi have you got made some progress ? I would like to release 1.6.0 somewhere like mid February and want to know if we could include this XML assertions

Sorry. Unfortunatelly, I had no time last month to handle this :(. But on Febuary 4 there will be a hackathon in my company and I will be working exclusively on this issue.

@mpi : no problem, we all do that on our spare time (or in hackaton !) tell me if you need me to clarify some points.

My own take on XML validation: https://github.com/j-maly/SchematronAssert (based on AssertJ).

There is also xmlunit2: https://github.com/xmlunit/xmlunit

@joel-costigliola You closed the pull request for this issue with:

I'm closing this issue but I might reconsider if a contributor wants to spend time on it.

I guess you also meant close this issue?

yes, main reason is because XML Unit 2 is actively developed and it's a "full time" project to get XML assertions, I just don't have time to do it properly.

For reference there is a pull request to add AssertJ support to XMLUnit 2: https://github.com/xmlunit/xmlunit/pull/120

we've just released XMLUnit 2.6.1 with the new xmlunit-assertj module, see https://github.com/xmlunit/user-guide/wiki/XPath-Support#multiplenodeassert--singlenodeassert

I created https://github.com/assertj/doc/issues/11 to reference XMLUnit

Was this page helpful?
0 / 5 - 0 ratings