2

I am using Ready API/SOAP UI. I added a SOAP request and I get a SOAP response XML. My response object has up to 40 Key/Value pairs.

I have functional tests to specifically test each.

  • Loop through the whole ArrayOfObjects and Assert if the Key exists and if it exists assert the value.

Can I get a working solution for this scenario. I am unable to do assert on the output object.

SOAP structure looks like this:

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <soap:Body>  
     <ArrayOfallObjects>
       <ArrayOfObjects>
          <Key>Key1</Key>
          <Value>Value1</Value>
       </ArrayOfObjects>
       <ArrayOfObjects>
          <Key>Key2</Key>
          <Value>Value2</Value>
       </ArrayOfObjects>
       ---------------
       <ArrayOfObjects>
          <Key>Key40</Key>
          <Value>Value40</Value>
       </ArrayOfObjects>
     </ArrayOfallObjects>   
   </soap:Body>
</soap:Envelope>

And I am using groovy script snippet as below

//Code Snippet Starts//    
def groovyUtils = new com.eviware.soapui.support.GroovyUtils(context)    
def request = context.testCase.getTestStepByName("RequestName")    
def responseCurrentHolder = groovyUtils.getXmlHolder( request.name +"#Response")
responseCurrentHolder.namespaces["ns1"] = "https://test.com"
def nodes = responseCurrentHolder.getDomNodes( "//ns1:Response/ns1:Result/ns1:ArrayOfallObjects/ns1:ArrayOfObject/*" )
def nodeCount = responseCurrentHolder.getNodeValues("//ns1:Response/ns1:Result/ns1:ArrayOfallObjects/ns1:ArrayOfObject/ns1:Key").length

def object = [:]
for (def nodeIndex = 1; nodeIndex <= nodeCount; nodeIndex++) {    
def nodeKey = responseCurrentHolder.getNodeValues("//ns1:Response/ns1:Result/ns1:ArrayOfallObjects/ns1:ArrayOfObject[$nodeIndex]/ns1:Key/text()")    
def nodeValue = responseCurrentHolder.getNodeValue("//ns1:Response/ns1:Result/ns1:ArrayOfallObjects/ns1:ArrayOfObject[$nodeIndex]/ns1:Value/text()")

  object.put( nodeKey,nodeValue)
}
log.info "Object =" +object

// Code snippet ends//

And the object looks like:

Object =[[Key1]:Value1, [Key2]:Value2, and so on upto --,[Key40]:Value40]
Rao
  • 20,781
  • 11
  • 57
  • 77
Manjula K
  • 23
  • 1
  • 5

2 Answers2

3

You can use Script Assertion for the same soap request test step to verify the same without adding additional Groovy Script test step.

Not sure if above sample has the same xml structure (if not exact). Otherwise, adopt the changes to suit your need.

Here is the approach:

  • Since there is complex data to be verified, and there is key, value pattern; so define a map as expected data like you pointed in the last.
  • Read the xml response, and create similar map out of it. At times, it may require to sort the retrieved data by key (or other criteria based on the data).
  • Then check if both expected and actual data.

Script Assertion:

//Define expected data; using few elements as sample
def expectedMap = [Key1: 'Value1', Key2: 'Value2', Key40: 'Value40']

//Check if there is response
assert context.response, 'Response is empty or null'

//Parse the response
def xml = new XmlSlurper().parseText(context.response)

//Extract the data, create actual map and sort by key
def actualMap = xml.'**'.findAll {it.name() == 'ArrayOfObjects' }.collectEntries {[(it.Key.text()): it.Value.text()]}​?.sort {it.key}
log.info actualMap
assert expectedMap == actualMap

You can quickly try it online demo

Rao
  • 20,781
  • 11
  • 57
  • 77
  • Thank you so much Rao! I will try this meanwhile, I needed some help with the double brackets that i pasted in my code snippet earlier. And the object looks like: Object =[[Key1]:Value1, [Key2]:Value2, and so on upto --,[Key40]:Value40] instead i need something like you have def expectedMap = [Key1: 'Value1', Key2: 'Value2', Key40: 'Value40'] do you have recommendation to remove the extra brackets please? – Manjula K Oct 27 '17 at 16:45
  • @ManjulaK, have you tried at least demo to see it quickly? May that clarifies your query. – Rao Oct 27 '17 at 17:44
  • 1
    Also I wil be doing an assert of only one Key/Value per functional test, because its based on a key(configuration) file we use. – Manjula K Oct 27 '17 at 17:49
  • @ManjulaK, did not get you. If you are getting all the keys in a single response then isn't supposed to test all the keys? – Rao Oct 28 '17 at 08:13
  • Well not really based on the config key setting, it returns only one Key/Value pair. If the config setting is to bring all keys, response object will come back with all Key/Value pairs. Does this help? – Manjula K Oct 30 '17 at 14:51
  • Ok, it should be able to verify even that, just use only those keys values in the `expectedMap`. – Rao Oct 30 '17 at 16:10
  • thank you Rao. I had to make some minor modifications to your code and it seems to be coming back with what I want. I have some bunch of tests to run to fool proof that this code works, for now seems to be looking fine. – Manjula K Oct 31 '17 at 21:20
  • @ManjulaK that would be the case always, because you put a general question with sample data and need to adopt the solution to your actual case. Appreciate if you can accept it as [answered](https://stackoverflow.com/tour) – Rao Nov 01 '17 at 01:33
1

The below code first get all keys in an array(x) and all values in another array y(x). You may add them in a map if not you can directly assert values

The below is one of the easiest and simpler way of validating key value pair

Just replace the 'First Step' with the name of the step where response is generated

def groovyUtils = new  com.eviware.soapui.support.GroovyUtils(context)

def response = groovyUtils.getXmlHolder("First Step#Response")

def x = response.getNodeValues("//*[local-name()='ArrayOfObjects']//*[local-name()='Key']")
for ( def keys in x)
{
log.info keys
}
 def y = response.getNodeValues("//*[local-name()='ArrayOfObjects']//*[local-name()='Value']")
for ( def values in y)
 {
log.info values
}

log.info "total keys are " + x.size()

for(int i = 0 ; i < x.size() ; i++)
{
 log.info " key = " + x[i] + " Value = " + y[i] 
}

Here is the result when i ran the above script

Sat Oct 28 14:41:57 IST 2017:INFO:Key1

Sat Oct 28 14:41:57 IST 2017:INFO:Key2

Sat Oct 28 14:41:57 IST 2017:INFO:Key40

Sat Oct 28 14:41:57 IST 2017:INFO:Value1

Sat Oct 28 14:41:57 IST 2017:INFO:Value2

Sat Oct 28 14:41:57 IST 2017:INFO:Value40

Sat Oct 28 14:41:57 IST 2017:INFO:total keys are 3

Sat Oct 28 14:41:57 IST 2017:INFO: key = Key1 Value = Value1

Sat Oct 28 14:41:57 IST 2017:INFO: key = Key2 Value = Value2

Sat Oct 28 14:41:57 IST 2017:INFO: key = Key40 Value = Value40

Gaurav Khurana
  • 3,423
  • 2
  • 29
  • 38
  • 1
    Thanks Gaurav. Lemme give it a try, – Manjula K Oct 30 '17 at 14:53
  • 1
    Hi Gaurav I tried your method. Instead of Log.info "Key".. I am adding the contents of Array of Key/Value into String so I can assert directly using that ex- for(int i = 0 ; i < x.size() ; i++) { String s = x[i] + "= " + y[i] } but I am doing assert on s == 'Key1=Value1' it throws an error stating no such property :s for class – Manjula K Oct 30 '17 at 20:27
  • Hi Manjula, the reason is s is declared within for loop, so it has a scope inside for loop. Assertion is run outside the loop so its not able to find s.Declare the variable s before the for loop, or try to put assertion inside the for loop just for testing if for x[0] its working fine or not – Gaurav Khurana Oct 31 '17 at 16:50
  • I did that, but I dont want to use the position of the Key/Value, as it the response , array objects position will change based on the config key. I tried doing assert x[i] == 'Key2' and assertion failed.Although Key2 is part of the x[i] array.. I thought it would be easy to assert a string so what i did in my earlier comment code.within the for loop I am building a string s variable by adding x[i] + y[i] and then assert on s. I tried inside the for loop as well. any other thoughts? – Manjula K Oct 31 '17 at 20:09
  • As you are not aware about the position of key/value. i.e. it can come at 5th position or at 10th also. So you should not use assert. Just check if x[i]='Key2' for all values of i say(1 to 10) if it matches set the flag found='true' and break the loop. then you can check outside the loop assert found=='true' if there was a match found inside the loop then system will consider the testcase pass. if the value of found!='true; it means key value pair was not found. – Gaurav Khurana Nov 05 '17 at 08:45