XQuery in soapUI Part 2: Where and Order By Clauses

In the last post we took a look at the basic syntax of XQuery expressions in soapUI, including for and return clauses.  In this post we'll look at the optional where and order by clauses, which can add more complexity to expressions.

The XQuery where clause is very similar to the SQL where clause; it allows you to provide an additional filter on the base data set selected in your for clause.  In the last post we created an XQuery example using the Euro 2012 web service that retrieved data for each player returned in the AllPlayersNames test request.  Let's say we wanted to narrow down the list of players to include only members of the German national team.  We could adjust the query by adding a where clause just after the for clause:


In this case the where clause (where $x/m:sCountryName = 'Germany') whittles down the full set of tPlayerNames elements returned by the for clause, keeping only those that satisfy the condition of the where clause (in this case, those where the sCountryName child element equals "Germany").

Many of the same functions available in XPath expressions can also be used in XQuery expressions; the following is a valid where clause, for example:

where starts-with($x/m:sName/text(),'M')

The starts-with function takes two arguments and returns true if the first argument (in this case, the value of the sName element) begins with the second argument ("M").

In many cases, the choice to use a where clause may come down to preference; it's possible to achieve the same end result by using predicates with your for clause XPath expression.  This XPath expression in the for clause returns only German players (equivalent to the first where clause example):

for $x in //m:tPlayerNames[m:sCountryName='Germany']

Likewise, the following is equivalent to the second example, returning only those players with names starting with "M":

for $x in //m:tPlayerNames[starts-with(m:sName/text(),'M')]

For readability, however, you may find using where clauses preferable to the extended for clauses.

If a web service returns data in an arbitrary order (i.e., changing with each request), it presents a problem for XQuery assertions, which check for an exact match-- order absolutely matters.  For situations like these, an XQuery order by clause is necessary.  As you might expect, the order by clause is used to sort XQuery results by some node's value, ensuring results are always in the same order for evaluation by the assertion.  The order by clause is added before the return clause; here's an example of a complete XQuery expression including a for, where, order by, and return clause:


This example selects tPlayerNames elements from the response (the for clause), filters out only those elements with sName child element values that start with "M" (the where clause), orders the results by the value of the sName child element (the order by clause), and finally returns the values of the sName and sCountryName child elements for each tPlayerNames element, formatted within identifying tags (the return clause).

It's also possible to specify multiple values for the order by clause, establishing primary, secondary, etc. sort criteria.  For example, you can change the order by clause in the example above to the following to use sCountryName as the primary sort value and sName as the secondary sort value:

order by $x/m:sCountryName/text(), $x/m:sName/text()

The beginning of the results from this modified XQuery expression look like this:


As expected, results are sorted by country first, with players from the same country further sorted by name.

As usual when discussing XML-related topics, I highly recommend checking out W3Schools.com (available from the Useful Links section on the right) to find more information about using XQuery expressions.

XQuery in soapUI Part 1: For and Return Clauses

A few weeks ago I spent a few posts looking at XPath assertions in soapUI; in this post I'll take a look at XQuery assertions.  XQuery assertions can be used to retrieve data from XML using a SQL-like syntax.  The advantage of XQuery over XPath is that it can be used to check multiple node values with a single expression.  XPath expressions in soapUI must resolve to a single value (a count, a Boolean, a node, a node value, etc.); while you can use an XPath expression to validate some large chunk of static data, XQuery provides a little more flexibility, allowing you to pick and choose the nodes you'd like to have returned-- particularly useful in cases where there's a mix of static and dynamic data.

For an example, let's look at the Euro 2004 web service I introduced a few posts back and look at the AllPlayerNames request.  You can download a stripped down "test suite" consisting of a single test case here.  Import the project into soapUI and run the test request; it should return a list of participating players in the Euro 2012 tournament:


Let's say (strictly for the sake of this example) we're only interested in validating the iId, sName, and sCountryName values for each player, verifying they match their expected values.  Expand the Assertions panel for the test request, click the icon to add a new assertion, and select the XQuery Match assertion type (part of the Property Content group in the Add Assertion dialog) to bring up the assertion editor.

As with XPath assertions, you'll need to make some namespace declarations; click the Declare button at the top of the editor to let soapUI do this for you.  The XQuery expression below returns the iId, sName, and sCountryName values for all players; enter it beneath the namespace declarations as shown:


Click the "Select from current" button to evaluate the XQuery expression.  Here's a snippet of the results:


Let's break down the expression, starting with the for clause: for $x in //m:tPlayerNames.  If you're familiar with for-in or foreach-in loops in some programming languages, used to iterate through a collection and perform some action on each of its members, this is a bit similar.  The for clause here essentially translates to "for each member in the set of elements returned by //m:tPlayerNames..."  The clause also assigns those elements to the variable $x in subsequent lines of the expression.

The return clause does the heavy lifting, retrieving data associated with each element via XPath expressions.  For example, $x/m:iId/text() returns the value of the iId child element for each element. The text() function may be new for some-- it simply indicates that you want the actual inner value (i.e., the value between tags) of an element.  With soapUI's XPath expressions, the text() function isn't necessary (specifying an element is enough to indicate you want its value and not the node itself), it is required for XQuery expressions.

Tags are used to group and organize expression results.  Experimenting a little bit with the expression, you'll see a couple of general rules.  If the XPath expression in the for clause returns multiple nodes, the entire expression should be wrapped in tags (like the "playerList" tag above).  Likewise, you'll receive an error if you try to alter the example expression by removing the "player" tag around the return XPath expressions-- because there are multiple XPath expressions applied to each element, a tag is needed to separate each element's returned data (each id, name, and country set).  The "id", "name", and "country" tags are not in fact necessary, but they make the results more readable.

Within tags, brackets ( "{" and "}" ) are used to identify expression content that needs to be evaluated, as opposed to literal text, which can also be included between tags.  Here's a variation on the example expression that includes some literal text:


Here's what the result looks like:


As you can see, the literal characters within the tags (but outside the brackets) are left intact in the expression output.

Now that you're familiar with the basic syntax of XQuery expressions, we'll look at where and order by clauses in the next post.

REST Services and JSON in soapUI Test Suites

In the previous post I walked through adding a REST service to a project in soapUI; as a quick recap, here's a screenshot of where we left the project, with several REST requests:


As with SOAP services, once a REST service has been added to a project soapUI can automatically generate a test suite for the service.  Right-click on the service's node in the workspace tree and select "Generate TestSuite" from the context menu.  The Generate Test Suite dialog looks very similar to the corresponding dialog for SOAP services, allowing you to choose the resources for which you'd like to generate tests, whether you'd like all of the generated tests grouped into a single test case or assigned to their own test cases, etc.:


Let's leave the default options and click OK.  A test suite is generated with one test case for each of the REST service resources we defined previously.  By default, test requests use the parameter values that were set when the corresponding service request was added to the project.  However, these values can be changed in a test request's parameters table, and you can use them with property expansion.  Open the cardId test case and create a test case property called testCard and give it the value "chain-reaction".  Open the editor for its lone test request (Retrieve Individual Card Info) and use soapUI's property expansion syntax to specify the testCard property of the test case as the value of the test request's cardId parameter-- enter "${#TestCase#testCard}".  Click the Send button (the green arrow) for the test request.  Looking at the response, we can see that the data returned does indeed correspond to the card named Chain Reaction:


Remember that you can specify different parameter types in the parameter table, so you can use property expansion with any of them: URI parameters, resource path parameters, request body parameters, etc.

Let's move on to creating an assertion.  Up until now in my posts I've focused on web services that return response data as XML; this REST service gives us an opportunity to look at how soapUI handles JSON data.  SoapUI's solution for dealing with JSON data is really pretty straightforward-- it generates an XML representation of the same data set.  Consequently, all of the same XML-based content assertion types are available to use with JSON response data.  Note the tabs running along the left side of the panel showing the response data, and (if necessary) click on the one labelled "XML" to view the response in XML format.


Click on the Assertions button at the bottom of the Request Editor to open the Assertions panel, click the Add Assertion button, and add a new XQuery Match assertion.  The service returns data for multiple editions of the same card, so we'll use our assertion to confirm some expected values for the two editions of the Chain Reaction card.  Click the Declare button at the top of the assertion's configuration dialog to add a namespace declaration and add an XQuery expression to return data for the card's editions; the expression with its declaration should look something like this:


Click the "Select from current" button to capture the expected result of the expression, then save the assertion with the test request.  When dealing with XML-based assertions and JSON response data, note that even though the XML is auto-generated by soapUI, a namespace declaration and namespace prefixes are still needed.  Also be careful of extra tags in the XML (such as the "e" tags around each set of edition data) that do not exist in the original JSON but are inserted by soapUI to delineate some JSON data structures in the conversion.