Forum Discussion

performerj's avatar
performerj
Occasional Contributor
8 years ago

Reusable assertions for REST error handling in SoapUI

I've been asked to come up with a way to provide reusable assertions for validating standard error responses (HTTP Status Codes 400, 403, etc.) so that those who develop other SoapUI TestCases that encounter errors don't have to code the same validations of HTTP status codes and JSON error response payload validation over and over again.

 

Since it does not appear to be possible to call one test case from another across projects, I thought the next best thing would be to be to come up with a shared Groovy script library to do these error validations.

 

Is there a Groovy technique that can be used to invoke the same function that is in the native SoapUI Json Schema Validator Assertion?  I imagine something like that can be done using JsonSlurper functionality, but I am not familiar enough with Groovy scripting to code that by myself?

 

Any help would be much appreciated.  Thanks in advance.

  • performerj's avatar
    performerj
    8 years ago

    I came up with the following which works at the script assertion level.

     

    // Logic for comparing response to JSON schema in Groovy
    import groovy.json.JsonSlurper
    def responseStatus = messageExchange.responseHeaders['#status#'][0]
    if ( responseStatus != 200 ) {  // Error code, make sure we got the confirmation message. 
      URL schemaUrl = new URL("https://developers.adp.com/static/Swagger/confirmmessage-schema.json")  // Create URL object in Groovy.
      def jsonSchemaMap = new JsonSlurper().parseText(schemaUrl.text) // Slurp JSON schema data into a Groovy map.
      def ResponseMessage = messageExchange.response.responseContent   // Fetch the JSON payload from the response message.
      def jsonResponseMap = new JsonSlurper().parseText(ResponseMessage)  // Slurp JSON response data into a Groovy map.
      def schemaKeys = jsonResponseMap.keySet() // Get the list of keys from the JSON schema.
      def responseKeys = jsonResponseMap.keySet()// Get the list of keys from the JSON response.
    
      assert schemaKeys == responseKeys  // Assert that the key lists from the JSON schema and the JSON response should match.
                                         // This is our indicator that we got a valid confirmation message.
      }
    else assert responseStatus == 200    // Otherwise, assert we got the normal expected response (HTTP Status Code = 200).

    From here I think it is mainly a matter of packaging things with classes, etc. to prepare for reuse from a script library.

     

  • nmrao's avatar
    nmrao
    Champion Level 3

    Your idea is in the right direction. Use script assertion and call the method from Script library.


    However, you might still need to add script assertion and make call to validate the response code for the request calls as it depends on case to case and which case what response etc.,

     

     

    Here is some more details which might help you to proceed:

    Create a Groovy Class with following method (can be static one at least this scenario)
    validateHttpResponseCode(messageExchange, code) {

      //Your logic goes here to verify given code

    }

    • nmrao's avatar
      nmrao
      Champion Level 3

      Here is sample Class & Script Assertion using Script Library

       

      class:

       

       

      class HttpResponseValidater {
          
          static def getActualCode(messageExchange){ messageExchange.responseHeaders['#status#'][0] }
          
          static def isCodePresent (messageExchange, code) { 
              def actualCode = getActualCode(messageExchange)
              println "Response has the http code : ${actualCode}"
              actualCode.contains(code.toString())
          }
          
          static assertStatusCodeExists(messageExchange, expectedCode, message=null) {
              def result = isCodePresent(messageExchange, expectedCode) 
              def mess = result ? { 'Response code is verified successfully' } : { def m = message ?: 'Response code is not matching with actual code'; m }
              assert result, mess()
          }
          
          static assertStatusCodeNotExists(messageExchange, expectedCode, message=null) {
              def result = isCodePresent(messageExchange, expectedCode) 
              def mess = !result ? { 'Response code is verified successfully'} : { def m = message ?: 'Response code is matching with actual code'; m }
              assert !result, mess()
          }
          
      }

       

      Hoping that you know how to place the above class in the Script Library. Otherwise, please refer documentation.

       

      Script Assertion for the request test step and call above library:

       

      Assert for Code Exists(+Ve)

       

       

      //Use below to assert the response code is 200 and on failure show the given message
      HttpResponseValidater.assertStatusCodeExists(messageExchange, 200, 'show this message on test fail')

       

      or 

       

       

      //Use below to assert the response code is 200 and code it self handles the showing the error message by default if user do not provide message which is 3 argument
      HttpResponseValidater.assertStatusCodeExists(messageExchange, 200)

       

      Assert for Code Not Exists(-Ve)

       

      //Obiviously when you are expecting 200 in http response code, you can optionally check there is no 404 http response code
      HttpResponseValidater.assertStatusCodeNotExists(messageExchange, 404, 'this is failed')
      

       

      Similarly, you can keep add more methods to the above class to verify certain header as well etc.,

       

      This way, end user do not have to bother about what he should write in script assertion. Just fixed statement with different parameter value to the respective test.

      • nmrao's avatar
        nmrao
        Champion Level 3

        Little Improved version with generic method names to verify headers (as status is also one of the header only)

         

        class HttpResponseValidater {
        
            	static def isHeaderPresent(messageExchange, header){ 
        		header in messageExchange.responseHeaders*.key
        	}
        	
        	static def getHeaderValue(messageExchange, header){ 
        		if (isHeaderPresent(messageExchange, header)) {
        			return messageExchange.responseHeaders[header][0]	
        		} else {
        			println "Response does not have the header[${header}] itself"
        		}
        		null
        	}
        
        	static def isHeaderValueMatching(messageExchange, header, headerValue) { 
        		def actualValue = getHeaderValue(messageExchange, header)
        		println "Response has the header ${header} and its value is : ${actualValue}"
        		actualValue?.contains(headerValue.toString())
        	}
        
        	static assertStatusCodeExists(messageExchange, expectedCode, message=null) {
        		def result = isHeaderValueMatching(messageExchange, '#status#', expectedCode)
        		def printMsg = result ? {'Response code is verified successfully'} : { def m = message ?: 'Response code is not matching with actual code'; m }
        		assert result, printMsg()
        	}
            
        	static assertStatusCodeNotExists(messageExchange, expectedCode, message=null) {
        		def result = isHeaderValueMatching(messageExchange, '#status#', expectedCode) 
        		def printMsg = !result ? { 'Response code is verified successfully'} : { def m = message ?: 'Response code is matching with actual code'; m }
        		assert !result, printMsg()
        	}
        	
        	static assertContentType(messageExchange, expectedContentType, message=null) {
        		def result = isHeaderValueMatching(messageExchange, 'Content-Type', expectedContentType)
        		def printMsg = result ? {'Response Content-Type is verified successfully'} : { def m = message ?: 'Response Content-Type is not matching with actual code'; m }
        		assert result, printMsg()
        	}
            
        }

         

        Script Assertion examples:

        // for asserting status code
        HttpResponseValidater.assertStatusCodeExists(messageExchange, 200, 'show this message on test fail')
        
        //for asserting content type
        HttpResponseValidater.assertContentType(messageExchange, 'application/soap+xml; charset=utf-8')

         

  • nmrao's avatar
    nmrao
    Champion Level 3
    On just rethinking, may be the example you mention (http code) is not good example or does not fit into writing re-usable user assertion as that is already available in ReadyAPI out-of-the-box.

    However, I would agree to you for other complex assertions such as verifying for certain data or verifying for certain headers etc.

    Never mind, the example I provided can be used as base and implement on your own as there is demand. And feel free to ask if there any specific question or having trouble to get an Idea doing things.