Search code examples
xmlgroovysoapuiassertionsnumeric-ranges

SoapUI GroovyScript assertion within (+ or - ) 0.05 of expected values


I currently have the following assertion script to check the value of three fields.

import org.junit.Assert

def response = messageExchange.getResponseContent() 
def xml = new XmlSlurper().parseText(response)              
def nodelist = xml.'**'.findAll{ it.name() == 'premium' } 
def assertions = [6.19, 6.47, 6.90]
def i=0

for (node in nodelist) assert node.toString().matches(assertions[i++].toString())

I am trying to get it so that the assertion will pass in the actual value is within 0.05 either side of the expected value.

The following script works when there is one value, but I am struggling to implement it with the assertion above.

import org.junit.Assert 
// get the xml response     
def response = messageExchange.getResponseContent()     
// parse it     
def xml = new XmlSlurper().parseText(response)      
// find your node by name   
def node = xml.'**'.find { it.name() == 'premium' }     
// assert       
if(node.toDouble() != 0.0)  
    Assert.assertEquals(0.00, node.toDouble(), 0.05)    

Edit

Sample Response:

<b:quote-data>
    <b:quote-data>
      <b:premium>6.13</b:premium>
    </b:quote-data>
    <b:quote-data>
      <b:premium>6.45</b:premium>
    </b:quote-data>
    <b:quote-data>
      <b:premium>6.91</b:premium>
    </b:quote-data>
 </b:quote-data>

Solution

  • Here are couple of things for failure in your case.

    • When you define a list as below, it considers each value type as BigDecimal type.
    • The extracted values should be coerced to the same type before comparison.

    Here is the sample to achieve the above:

    def expectedPremiums = [6.19, 6.47, 6.90]
    def xmlString = """<root xmlns:b="test">
     <b:quote-data>
           <b:premium>6.13</b:premium>
         </b:quote-data>
         <b:quote-data>
           <b:premium>6.45</b:premium>
         </b:quote-data>
         <b:quote-data>
           <b:premium>6.91</b:premium>
        </b:quote-data>
    </root>"""
    def xml = new XmlSlurper().parseText(xmlString)
    def premiums = xml.'**'.findAll {it.name() == 'premium'}*.toBigDecimal()
    println premiums
    

    Note that using sample fixed xml, you can use to for dynamic response like you are already doing.

    If you also need the logic for validation with tolerance, then use below along with above script.

    def tolerance = 0.05
    def failurePremiums = [:]
    expectedPremiums.eachWithIndex { expected, index ->
       if ((expected-tolerance) <= premiums[index] && premiums[index] <= (expected+tolerance)) {
         println "${premiums[index]} is in range"
       } else {
          println "${premiums[index]} is not falling in range, failed"
          failurePremiums[expected] = premiums[index]
       }
    }
    assert !failurePremiums, "Not matched data(expected vs actual) :  ${failurePremiums}"
    

    You can quickly try it online demo

    EDIT: Another suggestion

    When you are using script assertion, you can change below:

    From:

    def response = messageExchange.getResponseContent() 
    def xml = new XmlSlurper().parseText(response)
    

    To:

    def xml = new XmlSlurper().parseText(context.response)