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.

Adding REST Services in soapUI

In this post I'll take a long overdue look at REST (REpresentational State Transfer) services in soapUI.  For anybody new to REST, I recommend this article covering the basics.  REST is not a web service protocol in and of itself; it's a web service architecture that can be implemented with any protocol, although it's frequently implemented with HTTP.  Occasionally, there's some confusion that arises from this relationship-- something to remember when thinking about your approach to testing a service.  For example, you may encounter a simple HTTP service labelled as a REST service that doesn't really take advantage of REST's architectural principles.  In these cases, it may be easier or more straightforward to implement test requests as basic HTTP requests in soapUI.

The last few releases of soapUI have also been very REST-centric, focusing on improved support and ease-of-use when dealing with REST services.  Going back just a few releases, creating REST services in a soapUI project was much more involved and complicated.  Consequently, if you intend to work with REST services I recommend updating to the most recent version if you haven't done so already.  This post reflects the workflow in soapUI 5.0.

For these examples, I'll be using the REST service at api.deckbrew.com.  The service provides information about cards from a popular collectible card game (Magic: The Gathering).  I apologize-- for most of you this subject matter will probably seem very dry, but it was surprisingly difficult finding a freely accessible web service that provided resources that could be used to create some meaningful examples.  This service is also limited in that it only leverages the HTTP GET method; an ideal REST service example would also utilize other HTTP methods (corresponding to different actions that could be taken on the service's resources).

When adding a SOAP service to a project, soapUI uses its WSDL document to determine the service's operations, their parameters, etc.  REST services have WADL (Web Application Description Language), which is roughly equivalent to SOAP's WSDL, but frequently a WADL document is not provided for a REST service (as is the case with our example service).  In these cases, soapUI allows you to enter service requests and parses the requests to identify the service's components.

From the soapUI File menu, select the option to create a new REST project.  You'll be prompted to enter a URI for the service:


To generate a request for a filtered card search, enter the following for the URI (as one continuous line):

https://api.deckbrew.com/mtg/cards?page=1&type=&subtype=&supertype=&name=&oracle=&set=&rarity=rare&color=red&multicolor=false&multiverseid=&format=&status=legal

In the workspace tree, soapUI generates a new project containing a node for the service's Cards resource, along with method and request child nodes corresponding to the URI we entered.  Click on the request to see the generated GET request:


All of the parameters entered as part of the request URI (including those for which no value was provided) are listed in the Request Editor.  You can add extra information about the parameters via the panel below the table; designating whether or not a parameter is required, for example.

The Level column determines the parameter's "scope" within the service-- a parameter can be associated with the RESOURCE level or the METHOD level.  Associating it with the RESOURCE level means the parameter is automatically "inherited" by any other method(s) created for its parent resource; it's added by default.  Associating it with the METHOD level means the parameter is only applicable to that method.  For this example, we'll just leave the parameters set to the default (RESOURCE).

A parameter's Style column indicates how the parameter is implemented-- the QUERY style corresponds to the standard "?parameter1=value1&parameter2=value2..." format you see as part of this GET request's URI.  Although POST requests are not supported by this example REST service, the QUERY type is also used when sending parameters in this format as part of the body (as opposed to the URI), as with POST requests.  For a POST request (and other methods allowing parameters in the message body), a checkbox is displayed that allows you to specify that parameters should be added to the request body instead of the URI.


To see an example of a different style, let's try adding a request to get the details for a specific card.  Right-click on the service in the tree and select "New Resource" from the context menu.  Another prompt appears-- note that once the host for the REST service has been established (via our previously created request), it's no longer necessary to enter the full URI when adding more resources.  The resource path by itself is sufficient.  Enter the following in the prompt:

/mtg/cards/about-face

You'll be asked if you want to add the new resource as a child of the existing Cards resource.  The parameters we added for the Cards resource aren't relevant to the single card request, so we're just going to add it as a completely separate resource.  Click No to the prompt.

There are no URI parameters for this request.  Instead, the last part of the resource path is the parameter.  We used "about-face" as the individual card id, but we can change the id to retrieve information for other cards.  This is where the TEMPLATE parameter style comes into play.  Open up the Request Editor dialog and add a new parameter called cardId.  Set its value to "about-face" and set the parameter's style to TEMPLATE.  You'll see the parameter appended to the resource path at the top of the dialog, enclosed in braces.  Edit the path to remove the hard-coded text "about-face", leaving the parameter to indicate the card id to retrieve:


After adding some additional resources and modifying some names to make them more descriptive, here's what our service looks like in our project:


In the next post, I'll look at using the REST service in a test suite.