SoapUI Groovy: Slurping JSON in Script Assertions

Groovy has what’s called a JsonSlurper. This takes the given response and ‘slurps’ it so we can assert on various properties. All examples below are for Script Assertions, see my other Groovy post if you’d like to make these into actual Groovy Scripts within a Test Case. Also, a lot of these you can put into various loops (I’ve outlined a few) to check if values aren’t null, etc, but I’ve left them out for the most part just for simplifying the explanations.

See also Test Automation using the JsonSlurper and JsonBuilder for a way to create Json using similar techniques.

1) Assert values are correct for JSON Response

Response:

{
   "Id": 1,
   "Type": "String",
   "GUID": "String-ABC"
}

Script Assertion:

//imports
import groovy.json.JsonSlurper

//grab the response
def ResponseMessage = messageExchange.response.responseContent
//define a JsonSlurper
def jsonSlurper = new JsonSlurper().parseText(ResponseMessage)

//verify the slurper isn't empty
assert !(jsonSlurper.isEmpty())

//verify the Id, Type and Guid aren't null
assert jsonSlurper.Id != null
assert jsonSlurper.Type != null
assert jsonSlurper.GUID != null

//verify Id is 1
assert jsonSlurper.Id == 1

//verify Type and GUID are Strings
assert jsonSlurper.Type == "String"
assert jsonSlurper.GUID == "String-ABC"

2) Assert values are correct a level deep

Response:

{
   "Id": 1,
   "ObjectSummary": {
   "Type": "String",
   "GUID": "String-ABC"
   }
}

Script Assertion:

//imports
import groovy.json.JsonSlurper

//grab the response
def ResponseMessage = messageExchange.response.responseContent
//define a JsonSlurper
def jsonSlurper = new JsonSlurper().parseText(ResponseMessage)

//verify the slurper isn't empty
assert !(jsonSlurper.isEmpty())

//verify the Id, Type and Guid aren't null
assert jsonSlurper.Id != null
assert jsonSlurper.ObjectSummary.Type != null
assert jsonSlurper.ObjectSummary.GUID != null

//verify Id is 1
assert jsonSlurper.Id == 1

//verify Type and GUID are Strings
assert jsonSlurper.ObjectSummary.Type == "String"
assert jsonSlurper.ObjectSummary.GUID == "String-ABC"

3) Assert values that are returned in an array

Response:

{
   "Id": 1,
   "ObjectSummaries": [{
   "Type": "String",
   "GUID": "String-ABC"
   }]
}

Script Assertion:

//imports
import groovy.json.JsonSlurper

//grab the response
def ResponseMessage = messageExchange.response.responseContent
//define a JsonSlurper
def jsonSlurper = new JsonSlurper().parseText(ResponseMessage)

//verify the slurper isn't empty
assert !(jsonSlurper.isEmpty())

//verify the Id, Type and Guid aren't null
assert jsonSlurper.Id != null
assert jsonSlurper.ObjectSummaries[0].Type != null
assert jsonSlurper.ObjectSummaries[0].GUID!= null

//verify Id is 1
assert jsonSlurper.Id == 1

//verify Type and GUID are Strings
assert jsonSlurper.ObjectSummaries[0].Type == "String"
assert jsonSlurper.ObjectSummaries[0].GUID == "String-ABC"

4) A combination of the above using loops and defined functions

Response:

{
   "Id": 1,
   "ObjectSummaries": [{
   "Type": "String1",
   "GUID": "String-ABC1",
   "Description": "StringDescription"
   },
   "Type": "String2",
   "GUID": "String-ABC1"
  }],
  "OverallCount": 2
}

Script Assertion:

import groovy.json.JsonSlurper

def ResponseMessage = messageExchange.response.responseContent
def jsonSlurper = new JsonSlurper().parseText(ResponseMessage)

def i = 0
def x = 0

//as long as there are values in the array
while(jsonSlurper.ObjectSummaries[i]!=null){

  id = jsonSlurper.ObjectSummaries[i].Id
  type = jsonSlurper.ObjectSummaries[i].Type
  GUID = jsonSlurper.ObjectSummaries[i].GUID
  type = type.toLowerCase()

  if (CheckIfDescription(jsonSlurper.ObjectSummaries[i]) == true) {
  		//do something here
  }

  if (type.equals("String1") && CheckIfDescription(jsonSlurper.ObjectSummaries[i]) == true) {
      //you'd have your assertion here
  } else if (type.equals("String1") && CheckIfDescription(jsonSlurper.ObjectSummaries[i]) == false) {
     //another assertion
  }  else  {
    //some other random count assertion
   x++
  }
 i++
}

assert jsonSlurper.OverallCount == i

//function to check if Description exists
def CheckIfDescription(value)
{
  if (value.containsKey("Description") && value.Description != null) {
    return true
  } else {
    return false
  }
}

SoapUI Groovy: Creating valid JSON from Test Case Properties

Examples of creating valid JSON through SoapUI test case properties


Here’s some examples of how you can take values passed in from datasources (like Excel) and make them into valid JSON on the fly. The variable ‘request’ in each script is the test step that you are writing the JSON to.

Most basic form, create a map, convert the map to JSON
import groovy.json.*

//properties
def request = testRunner.testCase.getTestStepAt(4).getTestRequest()
def tcProps = testRunner.testCase.getProperties()

def map  = [:]

for(p in tcProps){		
 	if (p.value.getValue() != "") {
 		map.put(p.key, p.value.getValue())  					
	}
}


//create valid JSON
def builder =  new JsonBuilder(map)
def json = builder.toPrettyString()
request.setRequestContent(json)
Create an object from your properties
import groovy.json.*

//properties
def request = testRunner.testCase.getTestStepAt(4).getTestRequest()
def tcProps = testRunner.testCase.getProperties()

def map = [:]

for(p in tcProps){		
 	if (p.value.getValue() != "") {
 		map.put(p.key, p.value.getValue())  					
	}	
}


//create valid JSON
def builder =  new JsonBuilder()

def root = builder.SomeObject {	
	map.each() {key,value -> "${key}" "${value}"}
}

def json = builder.toPrettyString()
request.setRequestContent(json)
Take an object which is already in the properties (so you’ve already written the JSON out) and just put it to the request
import groovy.json.*

//properties
def request = testRunner.testCase.getTestStepAt(4).getTestRequest()
def tcProps = testRunner.testCase.getProperties()

def map  = [:]

for(p in tcProps){		
 	if (p.value.getValue() != "") {
 		map.put(p.key, p.value.getValue())		
	}	
}

//create valid JSON
def builder =  new JsonBuilder()

def root = builder {
	MyObject {
		map.each() {key,value -> "${key}" "${value}"}
}

def json = builder.toPrettyString()
//need to do this if using latest Groovy or else it'll escape all your quotes, etc
json = StringEscapeUtils.unescapeJava(json)
request.setRequestContent(json)
Create int arrays as valid JSON

This uses the method dropWhile and takeWhile which were added in 1.8.7 of Groovy (note: this is also the version that fixes the bug that then breaks the passing of objects so you need to unescape the json) and the function called simplisticParse, which I didn’t write, that credit goes to Tim Yates and saved me so much time.

import groovy.json.*
//properties
def request = testRunner.testCase.getTestStepAt(4).getTestRequest()
def tcProps = testRunner.testCase.getProperties()
def map  = [:]

//grab all the properties from the test case and put them in a map as long as they aren't empty or contain CD
for(p in tcProps){		
 			if (p.value.getValue() != "") { 
 			map.put(p.key, p.value.getValue()) 				
	}	
}

//create valid JSON
def builder =  new JsonBuilder()
def root = builder {
	map.each() {key,value -> 
	if (key.equals('IntArrayKey1') || key.equals('IntArrayKey2') || key.equals('IntArrayKey3')) {
		value = simplisticParse(value, Integer)
	"${key}" value
	}else {
		"${key}" "${value}"
	} 				
	}
}

def json = builder.toPrettyString()
request.setRequestContent(json) 

//parser for fixing JSON
def simplisticParse( String input, Class requiredType ) {
  input.dropWhile { it != '[' }
       .drop( 1 )
       .takeWhile { it != ']' }
       .split( ',' )*.asType( requiredType )
}

Update Groovy version for SoapUI

I came across an issue when writing some scripts where the version of Groovy that comes with SoapUI (1.8.0 just fyi..) didn’t have the methods I was looking to use. I found it’s pretty easy to update at least and I haven’t run into any issues so far (except 1..which lead to 2). Beware when passing in JSON objects through properties that previously would have not been escaped, consider yourselves warned…I’ll go into that code later.

Ahem, anyway, to update. Get the version of Groovy you want from here

Now go to: $SOAPUI_HOME/lib
Drop the jar file from the ’embeddable’ directory of your download into the above directory and start up SoapUI
Done.

Obviously it should go without saying but I doubt Smartbear would support it so use at your own risk. Plus if you’re looking to do this I figure you know what you’re doing anyway.

SoapUI Cheat Sheet: Properties

Most of this can be found on the SoapUI website. This sheet is all about setting, getting, assigning properties in SoapUI via Groovy scripts.

Referencing Properties from within Test Requests

//TestCase level
${#TestCase#MyProp}

//TestSuite level
${#TestSuite#MyProp}

//Project level
${#Project#MyProp}

Getting Properties…

-From a Groovy Script test step:

def testCaseProperty = testRunner.testCase.getPropertyValue("MyProp")
def testSuiteProperty = testRunner.testCase.testSuite.getPropertyValue("MyProp")
def projectProperty = testRunner.testCase.testSuite.project.getPropertyValue("MyProp")
def globalProperty = com.eviware.soapui.SoapUI.globalProperties.getPropertyValue("MyProp")

-From a Script Assertion on a test request:

def testCaseProperty = messageExchange.modelItem.testStep.testCase.getPropertyValue("MyProp")

Setting Properties…

-From a Groovy Script test step:

testRunner.testCase.setPropertyValue("MyProp", someValue)
testRunner.testCase.testSuite.setPropertyValue("MyProp", someValue)
testRunner.testCase.testSuite.project.setPropertyValue("MyProp", someValue)
com.eviware.soapui.SoapUI.globalProperties.setPropertyValue("MyProp", someValue)

-From a Script Assertion on a test request:

messageExchange.modelItem.testStep.testCase.setPropertyValue("MyProp", someValue)

-Set Test Suite property to a Json object from Script Assertion

//add a test suite property for a JSON object from a response of a given test case
//builder is the var of your JSON builder which is most likely 'jsonizing' a map
messageExchange.modelItem.testStep.testCase.testSuite.setPropertyValue("SomeObject", JsonOutput.prettyPrint(builder.toString()))

Assign Test Case properties to a map from Groovy Script test step

def tcProps = testRunner.testCase.getProperties()
def map = [:]

//grab all the properties from the test case and put them in a map as long as they aren't empty
for(p in tcProps){		
 			if (p.value.getValue() != "") { 
 			map.put(p.key, p.value.getValue()) 				
	}	
} 

Planning your project

My husband always says, “Plan the work, execute the plan.” That couldn’t be more true when you are deciding the best way to organize your project and is even more important if you plan on using dynamic sets of data.

I’ve seen test suites setup two main ways (or a combination):

1) Setup the real world scenario as a specific set of calls. For example, “Place an order”. You would include whatever flow is required for that to take place, from login to checkout. Behavioral driven testing.
2) Use DataSinks and loops on one call to iterate through a set of data. An example of this could be looping through an Excel spreadsheet.

Once you’ve worked out what variety of the above best suits your needs, you can start to build it out. Another thing to keep in mind is where you want or need your properties to live so they stay in scope. Properties in SoapUI can be at the test case, test suite, or project level. So, if you have a property at the test case level another test case within the test suite will not be able to access it.

My examples will be around Rest services with JSON using the second framework since the first is so unique depending on how your services are set up. My focus is on Rest because there’s less information out there about it, or that’s what I found Googling.