SiKing

July 5, 2013

dynamically create elements in a SoapUI request, JSON version

Filed under: automation — SiKing @ 10:50 am
Tags: ,

One of my previous posts “dynamically create elements in a SoapUI request” seems to be quite popular – 3rd most popular by the number of hits. Well recently I had to achieve the same feat, but this time in JSON for a REST call. So I thought I’d share.

With the release of version 1.8 Groovy introduced native support for JSON.

the challenge

Transform this response of one step:

{
  "leagueId": 22,
  "name": "Bruins at Sabres",
  "rotation": 1401,
  "eventId": 66069,
  "status": "ACTIVE",
  "leagueName": "NHL",
  "startTime": "2013-08-17T09:05:00.000-07:00",
  "home": {
    "selectionId": 1243,
    "name": "Sabres",
    "shortName": "SAB",
    "marketId": 0
  },
  "away": {
    "selectionId": 454,
    "name": "Bruins",
    "shortName": "BRU",
    "marketId": 0
  },
  "markets": [
    {
      "marketId": 428465,
      "name": "Money Line",
      "period": 11,
      "type": {
        "marketTypeId": 2,
        "basicType": "ML"
      },
      "selections": [
        {
          "selectionId": 454,
          "name": "Bruins",
          "shortName": "BRU",
          "position": "A",
          "priceId": 3560954,
          "price": 1.74074074,
          "usprice": "-135",
          "marketId": 428465
        }
      ]
    }
  ]
}

To make it look like this request of the next step:

{
  "bets": [
    {
      "stake": "10.201259570695608",
      "selections": [
        {
          "marketId": 428465,
          "position": "A",
          "price": 1.74074074,
          "selectionId": 454,
          "name": "Bruins",
          "priceId": 3560954,
          "shortName": "BRU",
          "usprice": "-135",
          "event": {
            "startTime": "2013-08-17T09:05:00.000-07:00",
            "leagueId": 22,
            "leagueName": "NHL",
            "eventId": 66069,
            "status": "ACTIVE",
            "rotation": 1401,
            "name": "Bruins at Sabres"
          }
        }
      ]
    }
  ]
}

the solution

The script ended up being surprisingly simple:

import groovy.json.*
def extractSelectionJson(String from) {

	def slurper = new JsonSlurper()
	def result = slurper.parseText(context.expand('${'+ from +'#Response}'))

	def selectionMap = [:]
	result.markets[0].selections[0].each {
		selectionMap[it.key] = it.value
	}

	def eventMap = [:]
	result.each {
		if(it.key.equals("away") || it.key.equals("home") || it.key.equals("markets"))
			return
		eventMap[it.key] = it.value
	}

	selectionMap["event"] = eventMap

	def builder = new JsonBuilder(selectionMap)
	testRunner.testCase.setPropertyValue("selection", JsonOutput.prettyPrint(builder.toString()))
}

Let’s have a look at what is going on.

Everything lives in the groovy.json.* namespace. The JsonSlurper reads and parses JSON using the .parseText() method which takes a string as an input. I will read all of my response into the variable result. I can now access any element in my response as an attribute of result.

Inside my script I will manipulate everything as a map.

In my request, the selections element is at a higher level of hierarchy than in the response. I will read that first (using result.markets[0].selections[0]) and iterate over all the elements. If you deal a lot with XML and XPath, keep in mind that arrays in XPath are one-based (the first one is numbered 1), however Groovy (and Java) arrays are always zero-based (first one is numbered 0); in this case we are manipulating everything in pure Groovy.

Next I build up the “event” map, where all the elements come from a higher level of the hierarchy than where they go into my request. Again, read all the elements and iterate over them (result.each), but this time I want to skip some in the if block.

Repackage everything back together in selectionMap["event"] = eventMap, and rebuild / convert it all back into JSON JsonBuilder(selectionMap).

Lastly there is no way to write this out directly into my test step request, similar to what I have been able to do with SOAP requests. So I write everything out to a SoapUI property, called selection.

If you are paying attention, I never addressed the bets and stake elements. That is because in my particular case I wanted to be able to manipulate the stakes on per test basis. My request now looks like:

{
  "bets": [{
      "stake": "${=Math.random() + 10}",
      "selections": [${#TestCase#selection}]
    }]
}

One more side note. When building all this up I ran into an issue. If any of the strings in my response above contained "\\" (double slash), the JsonSlurper crashed. This is a bug in Groovy, discussed here, and allegedly fixed in Groovy 1.8.4; SoapUI ships with Groovy 1.8.0. There are two possibilities how to work around this in SoapUI.

  1. When you read in the response, you have to read it in as slurper.parseText(context.expand('${'+ from +'#Response}').replaceAll("\\\\", "")). This obliterates all the double slashes, which in some cases may be undesirable.
  2. Install latest Groovy – I used Groovy 2.1.1. Copy the file $GROOVY_HOME/embeddable/groovy-all-*.jar to $SOAPUI_HOME/lib, and remove $SOAPUI_HOME/lib/groovy-all-1.8.0.jar. This could cause problems if you are running your tests on a CI machine that you do not have direct control over.

2 Comments »

  1. Hi
    I am new to groovy. Could you pls show the script before inserting item and after ? I am trying to insert an item/field with a value dynamically in my json -Rest -requst. Based on a condition I need to add ‘offerMinimum: 100 in my script. I am not capturing any from response. Here looks like you are using a property and updating the property with response info. My understanding might be wrong.

    Comment by Jayasree — April 23, 2014 @ 12:13 pm | Reply

    • Right. In SoapUI you cannot write directly into the Request. Actually you can, but it is a lot more work, and I did not show that here.
      I build up my entire Request and then write it to a property called “selection”. I then simply use property expansion in the SoapUI Request.

      It is entirely possible to build up just a part of a Request, like your item, and write only that to a property. Note that if you want this item to appear conditionally (only sometimes), you would have to be careful about commas and this would have to be part of whatever you write to your property, to correctly separate the JSON elements.

      Comment by SiKing — April 25, 2014 @ 9:55 am | Reply


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

The Rubric Theme. Create a free website or blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: