soapUI: Scripting Objects - MessageExchange Interface

This is a continuation of a series of posts attempting to review some of the objects (and methods) you're likely to encounter when you start scripting in soapUI.  To see the full soapUI javadoc, click here.

Common MessageExchange Methods

SoapUI's MessageExchange interface defines methods for retrieving information related to test requests, including request and response data.  Within a Groovy Script assertion, a built-in variable (messageExchange) provides access to an object of a class that implements the MessageExchange interface.  Several step result classes (including the WsdlTestRequestStepResult class) also implement the MessageExchange interfaces.  Some of the common methods of the interface (available to objects of all classes that implement the interface) include:

getEndpoint() : returns the target endpoint as a String
getRequestContent() : returns the content of the test request
getRequestContentAsXml() : returns the content of the test request (as XML)
getResponseContent() : returns the content of the response to the test request
getResponseContentAsXml() : returns the content of the response to the test request (as XML)
getTimeStamp() : returns the request time stamp as a long number (see below for an example of converting from long to a standard time format)
getTimeTaken() : returns the amount of time taken to process the request (in milliseconds)
- getRequestHeaders() : returns request headers as a StringToStringsMap object
- getResponseHeaders() : returns response headers as a StringToStringsMap object

A map (as implemented in the StringToStringsMap objects returned by the getRequestHeader() and getResponseHeader() methods) is similar to a list in that it's capable of storing multiple data items.  Map "entries" are stored as data pairs: a key and a value.  So while an item in a list is retrieved using its location in the list order (its index), a data value in a map is retrieved using its associated key.  If that explanation still unclear, see the example below using the getResponseHeaders() method, which illustrates retrieving data from a StringToStringsMap object.

Examples Using MessageExchange Methods

These coding examples use the PeriodicTable service I've used in many other posts and reflect a test request call made to its GetAtomicNumber operation.  The first example illustrates some of the methods illustrated above as they might be used in a Groovy Script assertion, called using the script assertion's built-in messageExchange variable:

log.info("MessageExchange class = " + messageExchange.getClass().toString())
log.info("Endpoint = " + messageExchange.getEndpoint())
log.info("Request Content = " + messageExchange.getRequestContent())
log.info("Response Content Xml = " + messageExchange.getResponseContentAsXml())
log.info("Time Taken = " + messageExchange.getTimeTaken() + "ms")
//Using a map: get the map and assign it to variable respHeadersMap
respHeadersMap = messageExchange.getResponseHeaders()
//Retrieve the map's keys and assign them to a list, respHeadersKeys
respHeadersKeys = respHeadersMap.getKeys()
log.info("Response Headers info:")
/*Use a for loop to step through each key in the map and
  use the map's get function to get each key's corresponding
  map data.  The get function takes two arguments: the first
  is the key for which you'd like the corresponding data, the 
  second is a default value if the key can not be found in the map.*/
for(key in respHeadersKeys){
 log.info("   " + key + ": " + respHeadersMap.get(key,"NONE"))
}
//To clarify, here's the Date header retrieved again:
log.info("   Date (again): " + respHeadersMap.get("Date","NONE"))
/*And here's a call to retrieve from a key that doesn't exist;
  the default value of "NONE" is used instead.*/
log.info("   Bogus: " + respHeadersMap.get("Bogus","NONE"))

The script log output looks something like this:



As I mentioned above, you're not restricted to using these methods with the messageExchange variable in script assertions-- you can use them with any class that implements the MessageExchange interface.  Here's another example taken from a Groovy Script step that uses a WsdlTestRequestStep object to invoke some of the methods:

//Get the result for the first step, a test request step
//Assign it to variable tReqResult
tReqResult = testRunner.getResults()[0]
log.info("tReqResult Class = " + tReqResult.getClass().toString())
log.info("Endpoint = " + tReqResult.getEndpoint())
log.info("Request Content Xml = " + tReqResult.getRequestContentAsXml())
log.info("Response Content = " + tReqResult.getResponseContent())
//Assign the value returned by getTimestamp() to variable timeStampAsLong
timeStampAsLong = tReqResult.getTimestamp()
//Use long value stored in timeStampAsLong to create a new Date object, assigned
//to variable timeStampAsTime; this can be used to get a "friendly" date format.
timeStampAsTime = new Date(timeStampAsLong)
log.info("Time Stamp = " + timeStampAsTime)

And the expected output:

Beginning soapUI Scripting 5: Groovy Assertions

So far we've looked at a few scripting "containers" in soapUI-- components where you can easily insert Groovy script to extend or customize functionality-- including Groovy Script test steps and set up and tear down scripts at the test case and test suite levels.  In this post we'll look at Groovy Script assertions, which are useful in situations where soapUI's built-in assertions don't quite fit the bill.

Script assertions can be added to a test request through the standard Add Assertion dialog, launched from the test request editor window:



Test Request Editor (Add Assertion button outlined in red)

Once you select Script Assertion (listed in its own Script category) as the type of assertion you want to add, click the Add button and provide a name for your new assertion to bring up an empty Script Assertion window:



Script Assertion Editor

As with other scripting components, script assertions come with several built-in variables.  We've already seen the log and context variables with Groovy Script steps and set up and tear down scripts, but script assertions also come with the messageExchange variable, which provides quick access to request and response data.

Here's a quick example of some script assertion code based on the periodic table service I've used in other posts (you can download the very, very small project here to play around with the script assertion yourself). It essentially replicates the functionality of a standard Contains assertion, looking for the appropriate string in a response from the service's GetAtomicNumber operation for the element hydrogen:

responseData = messageExchange.getResponseContent() log.info(responseData) assert responseData.contains("<atomicnumber>1</atomicnumber>")
The first line grabs the content of the test request's response (as a string) and assigns it to the variable responseData; it also illustrates the convenience of the built-in messageExchange variable: we're able to access test request data with a single method call (I'll look at some of its other methods in a separate post in the near future). The second line is strictly for informational purposes; it just writes the responseData string to the script log.  The assert keyword is introduced in the second line.  It asserts that the expression following the keyword is true (in this case, we're asserting that the responseData string contains the correct atomic number for hydrogen. If the asserted expression is false, the assert statement (and consequently, the entire script assertion) fails.

The assertion as written should pass, but try changing the substring in the contains method to something else-- changing the atomic number to 2, for example.  You'll see that the assertion is flagged as a failure in the UI just as a standard assertion failure would be flagged:



Script Assertion Failure

Learning Resources: Coursera

A few months ago I wrote a post on several learning resources for Java; this time around I thought I'd write about a single learning resource for... well, quite a lot: Coursera.  I imagine most people are already familiar with it, but for those who aren't, Coursera provides online courses in a variety of subject areas for free.  Founded by two Stanford faculty members, it counts some top-notch institutions among its partners (70+ as of this writing).

Currently, courses are offered for free, but Coursera ultimately intends to generate revenue.  To that end, they've begun implementing some pay services; for example, they recently introduced a special service called Signature Track that (for a premium) awards students who complete courses with certificates securely tied to their identities, making it easier to share them with potential employers, etc. It may be their hope that revenue from these ancillary services will enable them to continue providing the course material for free, but I suppose some sort of fee-based system isn't necessarily out of the question in the future.  All of which is to say: I'd recommend availing yourself of the service as soon as possible.

As with a "real" course, the material is broken up into units (normally weekly, in my experience), so you and your virtual classmates progress through the units together; course-specific online forums facilitate communication between students and teachers.  Lectures are delivered via online videos with short questions embedded throughout to gauge your understanding; you can listen to the lectures at your own pace (within the time frame for each unit, of course).  Quizzes at the end of each unit generally comprise part of your course grade, which may also include graded exercises, projects, and exams.

Given Coursera's format, it should come as no surprise that a large number of technology- and programming-oriented courses are offered.  While there are no courses (that I'm aware of) for learning Java, I would recommend the Learn to Program: The Fundamentals and Learn to Program: Crafting Quality Code courses offered by the University of Toronto.  As their names imply, they're intended to provide an introduction to programming concepts in general, but Python is the language of choice so they end up being pretty good introductions to Python specifically, too (Python is the primary scripting language used by Sikuli, the UI automation tool I've discussed in other posts).

If you're hesitant to jump into the pool and would like to sample a course to see if this learning method is right for you, there are currently two computer science courses available for self study: Introduction to Databases and Computer Science 101, both from Stanford University.  Without due dates and a live online forum (and there's no statement of accomplishment for completing self study courses) it's not quite the same thing, but at the very least you can get a sense of what online lectures and quizzes are like.  The Computer Science 101 course may seem very basic to people who work with computers on a daily basis, but for anybody unfamiliar with programming/scripting, the first three units teach some fundamental concepts including variables, dot notation, and flow control, albeit via a simplified proprietary Javascript-like language developed by the course instructor (Nick Parlante-- who also developed Google's Python Class).  The "image puzzles" in the course are also kind of cool.