Forum Discussion

richie's avatar
richie
Community Hero
11 days ago
Solved

GroovyScript - Extract specific number of attribute values from variable content response

Hey!

I've checked my groovy script notes which contains essentially all the groovy script snippets people have ever helped me with over the years - mostly from nmrao if I'm being honest - but I haven't got an example of what I need - sometimes I can expand the examples I already have to do what I need, but not this time.

I have a GET response JSON payload that can have 1 or many records in the response. 

Each record in the response will have an 'id' attribute value (JSONPATH --> x.data[0].id)

The 'data' array can have 1 or many records, so JSONPATH for the id attribute value for first record this would be x.data[0].id, but there could be 50 records or more (50 records, the JSONPATH of the id associated with the 50th record would be x.data[49].id)

I won't need to save all 50, or 100, or however many records there will be.  

I'd like to be able to specify the number of id values I save for later.

I want to save these 'id' values at TestSuite level for later. 

I'm not sure how many 'id' values I'll need - maybe only 5 or maybe 10 - I don't know yet, so I'd like to be able to specify how many 'id' values I extract and save on the TestSuite.


This is the groovy script so far - as I say above - it's all courtesy of nmrao

//Script Assertion
def json = new groovy.json.JsonSlurper().parseText(context.response)
//find all 'id' attribute values
def id_list = json.data.'id'.findAll() 
//List the 'id' attribute item count
log.info id_list.size
//Iterate thru each id, then stick them in a map, then once they're in a map, grab X instances of the 'id' values and split the map out and save them at TestSuite level
id_list.each { id ->

And that's as far as I've got.

I'm guessing I need to count the number of records so I don't try and grab more 'id' attribute values than actually exist causing the script to fail. I think I need a map and I've been googling - but it's beyond me - all the groovy script with maps I've got examples of,  mix multiple methods together and I've never been able to read exactly what's occurring in those lines of the groovy.  I know the groovy to save off a single property to TestSuite level for later use - but I don't know how to save off a variable sized number of attributes into separate properties for later use - especially as I'd like to grab a certain number of 'id' values from the total available - maybe from the first 10 records out of X returned.

I've attached the response payload that includes just a single record

Can anyone give me a steer please?

As always - I genuinely appreciate all/any help anyone can give me!

Cheers,

Rich

 

  • richie 

    You can quickly try this groovy to understand how this can be achieved in general.

    Follow inline comments:

    def range = 1..10
    
    println "Items in the range: $range"
    
    
    def startingIndex=0
    
    //Set this value, how many values to be stored 
    def endIndex=4
    
    //This is to ensure not to grab more than present in the list
    assert endIndex <= range.size(), 'Choose the endIndex less than list size'
    
    //Now get the sub list from original list
    def mySubList = range.subList(startingIndex,endIndex)
    println mySubList
    
    //In order to save data as custom property, coierce it to String
    def mySubListToString = mySubList.join(',')
    println mySubListToString //Save this at suite level
    
    //Convert string back to list when needed later
    def stringToList = mySubListToString.split()
    println stringToList

    If running the above from the ReadyAPI / SoapUI, use log.info instead of println

    Hope you knew how to store mySubListToString into Test Suite custom property.

    Note that all the properties in ReadyAPI are stored as string.

5 Replies

  • nmrao's avatar
    nmrao
    Champion Level 3

    richie 

    You can quickly try this groovy to understand how this can be achieved in general.

    Follow inline comments:

    def range = 1..10
    
    println "Items in the range: $range"
    
    
    def startingIndex=0
    
    //Set this value, how many values to be stored 
    def endIndex=4
    
    //This is to ensure not to grab more than present in the list
    assert endIndex <= range.size(), 'Choose the endIndex less than list size'
    
    //Now get the sub list from original list
    def mySubList = range.subList(startingIndex,endIndex)
    println mySubList
    
    //In order to save data as custom property, coierce it to String
    def mySubListToString = mySubList.join(',')
    println mySubListToString //Save this at suite level
    
    //Convert string back to list when needed later
    def stringToList = mySubListToString.split()
    println stringToList

    If running the above from the ReadyAPI / SoapUI, use log.info instead of println

    Hope you knew how to store mySubListToString into Test Suite custom property.

    Note that all the properties in ReadyAPI are stored as string.

  • richie's avatar
    richie
    Community Hero

    Ah nmrao  - that is brilliant man - really - I can use this and extend it for loads of stuff I'm working on - and yeah - I remember ReadyAPI groovy log.info rather than other groovy/java println and I'm good extracting to testsuite property and I've been casting between numerics and strings using .toInteger() / .toString() methods on a number of scripts I've been working on in the last week  - it was EVERYTHING else up to that point I was stuffed on. ;) 

    again - you are a Life Saver!

    cheers,

    rich

    • richie's avatar
      richie
      Community Hero

      Hey nmrao 

      Ok - I'm still struggling - if I'm understanding the code correctly - your code starts off as follows via a Script Assertion:

      def json = new groovy.json.JsonSlurper().parseText(context.response)
      log.info json
      
      def startingIndex=0
      
      //Set this value, how many values to be stored 
      def endIndex=4 
      
      assert endIndex <= range.size(), 'Choose the endIndex less than list size' 
      
      //Now get the sub list from original list 
      def mySubList = range.subList(startingIndex,endIndex) 
      log.info mySubList
      
      //In order to save data as custom property, coierce it to String
      def mySubListToString = mySubList.join(',')
      log.info mySubListToString //Save this at suite level

      so the JSONPATH of the first route_code out of the 4 I care about is  x.json.data[0].route_code

      HOW do I match the startingIndex variable (which you've got declared above) to json.data[0].route_code) so that the other 3 route_code values (with values json.data[1].route_code, json.data[2].route_code, json.data[3].route_code) are extracted also?

      Your comment on the line declaring the mySubListToString variable is the bit where I save my data as a custom testsuite property - but at this point I've got no data - I haven't yet extracted the x number of route_codes (4 in the case of the above script defined by the endIndex variable) - this is the bit I'm struggling with.

       

      Just so you know I'm not just letting you do all the heavy lifting without trying to solve myself - I did try playing around with the following to see if I could get a little further along (or at least increase my understanding) - cos the code below is based on what you've helped me out with before - I was hoping I could edit it to do what I need, but it only logs the first instance of the route_code value - I thought lines 5 & 6 might extract all the route_codes - but I realised I'm not using the it() method - I did try adding .it() in various places but I couldn't get it to work - I really need to buy a groovy for dummies book!

      // Log the first route_code
      log.info('First (index zero) route_code = ' + json.data[0].route_code)
      
      // Log all route_codes
      json.data.every{ prop ->
      	log.info('route_code = ' + prop.route_code) 
      }
      
      // Log all route_code with index
      json.data.eachWithIndex(){ prop, idx ->
      	log.info('route_code ' + idx + ' = ' + prop.route_code)
      }
      

      Been years since I've used ReadyAPI! when you were helping me with my groovy before and it's really showing!

      As always - appreciate your help!

      Cheers,

      Rich

       

  • nmrao's avatar
    nmrao
    Champion Level 3

    Glad to know. Need anything? otherwise Closing this as resolved?

  • nmrao's avatar
    nmrao
    Champion Level 3

    In the original post, it is mentioned 

    //find all 'id' attribute values
    def id_list = json.data.'id'.findAll() 

    id_list, this is nothing but range in the example where there are list of ids.

    However, in the latest post, route_code is being used which is not available in the attached .txt file (original post)

    You just get all the id/code what ever applicable and assign them to range variable. Otherwise, please show relevant data.