Beginning soapUI Scripting 7: More with the XmlHolder Class

You can download a project containing examples using the XmlHolder class (including the scripts covered in this post) here.  While I discuss XPath expressions here, a detailed explanation of how they work is beyond the scope of this post-- if you're unfamiliar with XPath, I highly recommend this tutorial at www.w3schools.com.

In my last post I introduced the XmlHolder class and demonstrated how it can be used with XPath expressions in your scripts.  In this post, I'll continue the discussion of the XmlHolder class with a look at some of the other assertion scripts included in the sample project I provided.

Let's actually start with the script assertion for the GetAtomicWeight test request (comments are removed in script excerpts for the sake of brevity); this one represents a basic case:

import com.eviware.soapui.support.XmlHolder

respXmlHolder = new XmlHolder(messageExchange.getResponseContentAsXml())
respXmlHolder.declareNamespace("ns1","http://www.webserviceX.NET")
CDATAHolder = new XmlHolder(respXmlHolder.getNodeValue("//ns1:GetAtomicWeightResult"))
atomWeight = CDATAHolder.getNodeValue("//AtomicWeight")
assert atomWeight == "1.00797"

If you've read my last post, this should all be familiar.  The import statement makes the XmlHolder class available in the script, and the next three lines pluck the CDATA section out of the response, putting it into the CDATAHolder XmlHolder object.  In line 4 of the main body of the script, the getNodeValue() method returns the value of the AtomicWeight element in the CDATA section, assigning it to the variable atomWeight, and the final line asserts that atomWeight matches the expected value of "1.00797".

Let's move on to a more interesting example in the script assertion for the GetAtoms test case:

import com.eviware.soapui.support.XmlHolder

respXmlHolder = new XmlHolder(messageExchange.getResponseContentAsXml())
respXmlHolder.declareNamespace("ns1","http://www.webserviceX.NET")
dataTableXmlHolder = new XmlHolder(respXmlHolder.getNodeValue("//ns1:GetAtomsResult"))
elementValues = dataTableXmlHolder.getNodeValues("/NewDataSet//Table/ElementName")
for (i in elementValues) {
 log.info(i)
}
countVal = dataTableXmlHolder.getNodeValue("count(/NewDataSet//Table)") 
assert Integer.parseInt(countVal) == 112
countAdamantium = dataTableXmlHolder.getNodeValue("count(//Table[ElementName='Adamantium'])")
assert Integer.parseInt(countAdamantium) == 0

Again, the first few lines (up to the creation of the elementValues variable) retrieve the CDATA string in our response XML and put it into an XmlHolder called dataTableXmlHolder.  The next lines illustrate a new method of the XmlHolder class, getNodeValues():

elementValues = dataTableXmlHolder.getNodeValues("/NewDataSet//Table/ElementName")
for (i in elementValues) {
 log.info(i)
}

The getNodeValues() method finds all matches in the XML it "holds" for a given XPath expression, putting their values into a list.  In this particular example, the GetAtoms operation returns all the element names in the periodic table (in a CDATA section); the call to getNodeValues() retrieves the names and puts them into a list called elementValues.  A for loop then iterates over the members of the list and prints them to the script log.

countVal = dataTableXmlHolder.getNodeValue("count(/NewDataSet//Table)") 

This is a call to the familiar getNodeValue() method, but in this case instead of returning the value of a single node we're using XPath's count() function to count the number of elements that match the expression "/NewDataSet//Table"; the result is assigned to the variable countVal.

assert Integer.parseInt(countVal) == 112

An assertion confirms the result of the count() function is 112.  The getNodeValue() method returns data as a string; here we're converting that string to a different data type.  The parseInt() method of Java's Integer class takes a string representation of a number as an argument and converts it to an integer.  Note that the method is called against the Integer class itself, not against an object of that class-- compare this to the getNodeValue() method in the previous line, for example, which is called against dataTableXmlHolder, an object of class XmlHolder.  Methods like this that are called against a class instead of an instance of an object are called static methods in Java.

countAdamantium = dataTableXmlHolder.getNodeValue("count(//Table[ElementName='Adamantium'])")
assert Integer.parseInt(countAdamantium) == 0

The final two lines illustrate using the getNodeValue() method with a more complex XPath expression to confirm a specific XML element or value does not exist in our response.  Here the count() function is used to count the number of elements named "Adamantium" in the result set.  Since adamantium isn't a real element, we assert that the count should equal 0.  Once again we use the parseInt() method to convert the result of the getNodeValue() function to an integer for the purposes of our assertion.

The last assertion script we'll look at comes from the GetElementSymbol test case:

import com.eviware.soapui.support.XmlHolder

respXmlHolder = new XmlHolder(messageExchange.getResponseContentAsXml())
respXmlHolder.declareNamespace("ns1","http://www.webserviceX.NET")
CDATAHolder = new XmlHolder(respXmlHolder.getNodeValue("//ns1:GetElementSymbolResult"))
symbolExists = CDATAHolder.getNodeValue("//Symbol = 'H'")
assert Boolean.parseBoolean(symbolExists)

The first few lines are the standard lines to deal with CDATA.  In the final two lines, another type of XPath expression is used with the getNodeValue() method; in this case, the expression is a comparison ("//Symbol = 'H'") that evaluates to true or false.  Again, since the method always returns its result as a string, we can use another static method, the parseBoolean() method of Java's Boolean class, to convert the result to an actual Boolean value to use in our assertion.

No comments:

Post a Comment

Please be respectful of others (myself included!) when posting comments. Unfortunately, I may not be able to address (or even read) all comments immediately, and I reserve the right to remove comments periodically to keep clutter to a minimum ("clean" posts that aren't disrespectful or off-topic should stay on the site for at least 30 days to give others a chance to read them). If you're looking for a solution to a particular issue, you're free to post your question here, but you may have better luck posting your question on the main forum belonging to your tool's home site (links to these are available on the navigation bar on the right).