Forum Discussion

richie's avatar
richie
Community Hero
7 years ago

Passing a json node (rather than the node's value) to a Property

Hi,

 

I need to grab a node name rather than the value from a .json request and pass it onto a subsequent .json request's body.

 

 

I have 2 api's I need to test.  1 is a POST followed by a GET.  The POST's response body has the same structure as the GETs request body.

 

My POST's api generates the following .json response

 

{
"$id": "1",
"UniqueAlphaNumericGUID": {
"$id": "2",
"StatusCode": 0,
"Outcome": "NewCall"
}
}

As you can see the 'UniqueAlphaNumericGUID' is the label (or json node) AND the value. 

 

SoapUI obviously treats this as the node rather than the value - but it is actually the unique reference of a record <-- so the node name changes for each record

 

I need to do a property transfer of this value to pass onto the GET's request body but I'm unsure how to do this because I need to pass the node name rather than the node's value.

 

groovyguygave me some groovyscript to parse XML and I tried converting it to parse .json but I'm not going to embaress myself by giving you what I got - its rubbish and doesn't even come close to working.

 

a java developer gave me the following to start me off:

import groovy.json.JsonSlurper
def json = "{\"\$id\": \"1\",\"UniqueAlphaNumericGUID\": {\"\$id\": \"2\", \"StatusCode\": 0,\"Outcome\": \"NewCall\"}}"
def myguid = ""
def test = new JsonSlurper().parseText(json)
println test.keySet()[1]

 

I would welcome any help/hints/advice anyone has!

 

thanks to all!

 

richie

 

 

 

 

 

 

 

  • richie, here is one more method to execute a REST step for multiple UIDs. In this example I have used your response with 3 different UIDs.

     

    I saved below response in a text file and reading it from there.

    {
       "$id" : "1",
       "1826d9a8-f542-e811-8120-5065f38b0571" : {
          "$id" : "2",
          "StatusCode" : 0,
          "Outcome" : "NewCall"
       },
       "beb19fbb-f542-e811-8120-5065f38b0571" : {
          "$id" : "3",
          "StatusCode" : 0,
          "Outcome" : "NewCall"
       },
       "ffe022cc-f542-e811-8120-5065f38b0571" : {
          "$id" : "4",
          "StatusCode" : 0,
          "Outcome" : "NewCall"
       }
    }

    groovy script to  extract GUIDs and iterate through them and execute RestTestStep for each GUID.

     

    import groovy.json.JsonSlurper
    
    def response = new File("c://users//XXXX//desktop//response.txt").text
    def json = new JsonSlurper().parseText response 
    
    def i = 0
    def UID = []
    
    json.each{
    	     if(it.key !='$id'){
                                  UID += it.key	                      
    	     }
    	     i++
       
    }
    
    
    log.info UID //## Array with 3 unique IDs ##//
    
    
    
    def j=0
    def uniqueId
    
    UID.each{
    	    //##Update TestCase Property with UID ##//
    	     uniqueId = UID[j]            
              testRunner.testCase.setPropertyValue("uniqueId", UID[j]) //store in a testcase property and then use this in subsequesnt RestTestStep//
              
              log.info "Executing RestStep for UID- $uniqueId"
              testRunner.runTestStepByName("YourRESTTestStep") // Execute RestStep Here //
    j++
    }
  • New2API

     

    WOW! - thanks so much!

     

    Really appreciate all the effort you made on my behalf!

     

    richie!

  • New2API's avatar
    New2API
    Frequent Contributor

    Hi Richie, I assume that you want to read the response from a REST teststep and extract a key from a json node.

     

    please check if this helps:

     

    I have stored your json response in a text file but you could use 

    def response = context.expand( '${'+TestStepName+'#Response}' )

     

    import net.sf.json.groovy.*
    import groovy.json.JsonSlurper
    
    def response = new File("c:\\users\\xxxxx\\desktop\\response.txt").text //or point to a rest response: def response = context.expand( '${'+TestStepName+'#Response}' )
    
    
    def json = new JsonSlurper().parseText response
    
    def jNode
    
     json.each{
     	       if(it.key.contains("GUID")){
     	                                  log.info it.key
     	                                  jNode = it.key
     	                                  //or store it in some property 
     	       }
     }
  • Have you tried using the JsonBuilder? 

     

    It seems you need a property expansion on the node, in effect making the node a property you can vary. I do property expansions on the value side and don't have a project to test out the concept below but here is an outline that maybe you can try:

     

    import groovy.json.JsonBuilder
     
    def json = new JsonBuilder()
     
    def nodeName = context.expand('${#Project#CPnode_name}').toString()
     
    def id1 = "1"
    def id2 = "2"
    def Outcome = "NewCall"
    def StatusCode = "0"
     
    def nodeValue = json "$id" : id2,
                               StatusCode : StatusCode,
                               Outcome : Outcome
     
    def root = json "$id" : id1,
                     "$nodeName" nodeValue
     
    def restRequest = testRunner.testCase.getTestStepByName(" < your test step name > ");
    restRequest.setPropertyValue('Request', json.toString())
    
    
    

     

    so that you should be able to get the unique alpha numeric ID variable substituted for $nodeName from the expansion.

     

    Like I say, I did not test it.

     

     

    • richie's avatar
      richie
      Community Hero

       

      Bill_In_Irvine@New2API,

       

      guys - thanks so much - I've tried both options but I'm still struggling so would welcome if you could answer some follow up questions based on your scripts.

       

      @Bill_In_Irvine

       

      I edited your script as you suggested, but I'm getting a runtime error 

       

      The edited script is as follows:

       

      import groovy.json.JsonBuilder
       
      def json = new JsonBuilder()
      def nodeName = context.expand('${#Project#CPnode_name}').toString()
       
      def id1 = "1"
      def id2 = "2"
      def Outcome = "NewCall"
      def StatusCode = "0"
       
      def nodeValue = json "$id" : id2,
                                 StatusCode : StatusCode,
                                 Outcome : Outcome
       
      def root = json "$id" : id1,
                       "$nodeName" nodeValue
       
      def restRequest = testRunner.testCase.getTestStepByName("GET Request - GET EOD Results");
      restRequest.setPropertyValue('Request', json.toString())

       

       

       

      Runtime error at line 12 which is the line that contains 

       

      def nodeValue = json "$id" : id2,

       

      The error response is 'MissingPropertyException: No such property: id for class:' 

       

      I'm sorry my groovy is rubbish - I've tried playing around with the line and the one before and after it - but I've had no luck.  Can you advise?

       

      So - that's the questions for Bill_In_Irvine all done

       

      New2API

       

      I updated your script to the following - but I'm struggling to write the data out to a property - your script is below:

       

      import net.sf.json.groovy.*
      import groovy.json.JsonSlurper
      
      def responseCntent = context.expand( '${REST Request - GET EOD Results#Response}' )
      
      def json = new JsonSlurper().parseText responseCntent
      
      def jNode
      
       json.each{
       	       if(it.key.contains("GUID")){
       	                                  log.info it.key
       	                                  jNode = it.key
       	                                  //or store it in some property 
       	       }
       }

       

       

      Now I was playing around with something I've used before (courtesy of @msiadak) which assigned a variable to the attribute value I wanted in the XML and allowed me to pass this to the properties step (as follows)

       

       

      def syncID = (holder["//Responses/VenueSyncSuccesses/VenueSyncSuccess/@VenueID"])
              def propertiesStep = context.testCase.testSteps["Properties"];
      propertiesStep.setPropertyValue("VenueID", syncID);

       

      I tried doing something like this for the .json - however - the info response the script currently returns is the whole .json response - I'm failing to see how I can extract ONLY the node names from this - dont I need to parse the .json and grab the GUID node names?  And even then I can't see how something like this would work for my .json because those node names are dynamic based on the records - i.e. the node name changes for each record returned in the results.

       

      Also - I cant see what the jNode variable is doing.  It doesn't appear to add anything to the current script nor the script results.

       

      as I say - my scripting skills are rubbish so I'm no doubt missing some obvious piece of info.

       

       

      Many thanks guys for all your help in this - you're really helping me out here.

       

      richie

      • Bill_In_Irvine's avatar
        Bill_In_Irvine
        Contributor

        Hi Richie,

         

        I assumed your POST request generated a json that had the $id in the name. Is the intention something like {id: 12,...} or is it like {12:12...}?  You will need a property expansion to get the value of id2.

         

        The contributor New2API has the approach that you probably want - to read the response in a groovy test step following the POST test step.  That way you will get whatever id name/value fields that are generated in the json of the POST response and you might then resolve the exception you got.

         

        But I think you still need to splice in the node for 

        UniqueAlphaNumericGUI

         

        I haven't read your response to New2Api but if you can retrieve  the json response without a problem in that suggested groovy script, just log.info json.toString() and see what it gets you. 

         

        You might then create another json variable (as a JsonBuilder object)  to construct a new json expression and copy the pieces from the response. Then splice in the nodeName as I first suggested. That "nodeName:" is the value that you expect changes every time you do a POST.

         

        It's kind of ugly, but it's just a concept I have and I have not tried it out.