My SoapUI Thoughts on Effective Testing in SoapUI

The Service Definition

The articles on mysoapui.net refer to the JSONPlaceholder API. This API supports many of the HTTP methods across several types of endpoint, and so provide a wide range of examples.

Setting up the service definitions in a SoapUI project

Recent versions of SoapUI offer several semi-automated ways of defining the services in an API. This is great where your developers are able to provide you with a WADL or Swagger definition file, but in some cases these resources aren’t available. There are several alternative approaches you can use when configuring the service definition in a SoapUI project, and choosing the best layout for your services can save you a great deal of time in the long run.

Prerequisites

  • A basic understanding of web service resources and methods

Goals

  • A SoapUI project containing a service definition that uses abstraction to manage multiple resource types and methods

I’d like to show how to configure the service definition in SoapUI as part of this blog because there aren’t too many blogs I’ve seen that go into this subject in depth. Even SmartBear’s own website doesn’t go into much detail in this area, which is a shame. There’s a huge benefit in abstracting your service definitions away from specific resource types where possible, so this page will explore some techniques in the analysis of an API which should help you produce a concise, easily maintained service definition.

Before we jump in, let’s take a look at what the JSONPlaceholder API offers.

Resources and Methods

The API implements six resource types, corresponding to six types of data structure:

  • posts
  • comments
  • albums
  • photos
  • todos
  • users

In turn each of these resource types supports the four main HTTP methods: POST, GET, PUT and DELETE, together with the less frequently tested methods OPTIONS, PATCH and HEAD. It’s easy to configure your service definition in SoapUI to cover all seven methods, so I’ll take you through this activity as part of this article.

In configuring the service definition for these resource types and methods, we also need to take into account that the API supports several different types of parameters for each resource type. For example, we see that we can call the GET method on the posts resource in the following ways:

Configuring the service definition – the wrong approach

Without doing any further analysis of the API, let’s look at how these GET methods might appear when configured in the service definition.

ServiceDefinitions00

This shows us four resources and five methods, and so far we’ve only configured requests for the GET method on the posts resource. If we were to proceed to configure REST test steps for these requests, the New RestRequest dialog would look like this. NewRequest01 That’s already quite a lot of methods to deal with, and we haven’t even started on the other resources yet. To illustrate, we have already configured five GET requests and can anticipate that we will need at least one more request for each of the PUT, POST, PATCH, HEAD, DELETE and OPTIONS methods, making 11 methods for the posts resource. With six resource types in the API, our completed service definition will contain 66 requests. Such a bloated service definition would lead to a complex and inflexible relationship between the requests and the associated test steps in the test cases.

(The limitations of this relationship are, in my opinion, made worse by SoapUI’s user interface. The New RestRequest dialog above is adequate when selecting from a small number of requests, but it scales poorly as the number of requests increases. These elements of the user interface in Ready!API are different but they don’t fully resolve the problem.)

The solution to the dangers of this simplistic service definition is to parameterize the resource definitions by way of template parameters.

Configuring the service definition – the right approach

The approach shown above to configuring the service definition is based on examining the resource types first. Alternatively, we can look instead at the methods and how they are reused between the resource types. For example, each resource supports the PUT method:

We can capitalize on this by abstracting the resource type and resource IDs into template parameters, indicated in SoapUI by braces e.g. PUT http://jsonplaceholder.typicode.com/{resourceName}/{id}.

This yields a request definition like this. PutRequest01

Key here is that when the request is executed as part of a test step, you can replace the value of the resourceName parameter with any of the other resource types: comments, albums, photos etc. This allows you to implement a one-to-many relationship between a request in the service definition and the associated test steps.

With this approach in mind, the service definition now becomes far more managable. Note that even if you have a WADL or Swagger definition file to work from, you will still need to go through this process of abstraction in order to produce a consise and manageable service definition.

In this example, I’ve implemented each of the HTTP methods as a child of the {resourceName}/{id} endpoint format. I’ve called this resource branch ‘Core’ in SoapUI, but you can name a resource branch in any way that’s meaningful to you. ServiceDefinitions01 You can see that I’ve also modelled the two other endpoint formats via branches which I’ve called Nested and Filters, with examples as follows.

As implemented in a REST test step, the request for the Nested GET method looks like this. GetChildResources01 Looking ahead just briefly, you can see that I’ve defined the request parameters via properties in a test step called ‘Props’. The value in doing this will become apparent in the discussion of data-driven test cases.

Request Formats

Before moving on from the service definition, you may have wondered why SoapUI implements a one-to-many relationship between the methods and the requests. You can see in our example that each method has one request, but you will have noticed that SoapUI offers the ability to create multiple requests for each method. If the resource defines the endpoint and the method defines the parameters, why would you need more than one request?

The answer is that multiple requests allow you to deal with an API that supports more than one request format. In the case of our POST requests, the JSONPlaceholder API supports a request body in JSON format, like this:

{
    "title": "${Props#title}",
    "body":  "${Props#body}",
    "userId": 1
}

To send data in this format, the request should be configured with the default Media type of application/json. But alternatively, the API also supports a request body like this: title=${Props#title}&body=${Props#body}&userId=${Props#userId}

In this case, the POST request should be configured with a Media type of application/x-www-form-urlencoded. Another commonly supported format is XML (application/XML). Given that you may want to implement tests for more than one of these formats, SoapUI allows you to create requests in the service definition specific to each required format. I mention this here for completeness; in this article we will deal with requests in JSON format only.

To wrap up this article, our service definition has successfully modelled the entire API via ten requests. Quite a reduction from the potential 66 we initially identified! There’s even more good news: if new resources are added to the API, our service definition may already be able to accommodate them without further modification. We can re-use the existing parameterised requests to model any new resources, as long as they use the same endpoint formats.

Now that we have our service definition in place, we can move on to the exciting subject of creating our first data-driven test case. (You are excited, aren’t you?)