A Basic Guide to Creating XML API Automated Checks

Checking out the Agoda YCS5 API

API testing is interesting. They’re very different from functional user interface testing because they do not require any UI, although programmers can provide testers some user interface for checking them if needed. They’re actually pretty straightforward to perform, they’re relatively easy to code, and they also provide fast feedback, unlike UI tests which often breaks easily, complicated to code, and are generally slow. I’ve been focusing on writing automated API checks for some apps in recent weeks and found out that the process was simple.

And here’s a basic guide of what that process looks like, in three steps:

  • Build the request content
    A basic XML request document source looks like this:

    <?xml version="1.0"?>
    <request>
       <element attribute="value">
       possibly a chain of more elements will show here
       </element>
    </request>

    In creating checks, this request source is just treated as a String data type, and then converted later to XML if necessary. I usually strip the source into three parts, namely header, footer, and body, and then just combine the parts. Usually it’s just the body part of the request that changes for scenario checks. How the actual request looks like, of course, is often found in the documentation of the API that you desire to test.

    For our example:

    header = <request>
    body = <element attribute="value"></element>
    footer = </request>

    The body can be further stripped down into many parts if desired, as it happens that some requests can contain multiple elements and sub-elements.

    In building a request, I just create a method that I can call anytime:

    def build_request(request_type)
       return get_header(request_type) + get_body(request_type) + get_footer(request_type)
    end

  • Send the request to the API endpoint, and retrieve the response
  • In API testing, what we check is the response of the API when we send a particular type of request to it. And to be able to generate a valid response from the API, we need to send our request to a valid endpoint. Sometimes that endpoint needs access credentials, sometimes it is the request themselves which contain said credentials. These details are often requested from the people who manage the API, or are sometimes found in your account information if the API requires you to create an account.

    As for how automation can send a request and generate a response, I often use the rest-client gem this way inside a method:

    def get_response(endpoint, request)
       begin
         response = RestClient.post endpoint, request, {:content_type => :xml}
       rescue => e
         response = e.response
       end
       return response
    end

  • Validate┬áthe API response
  • Checks are of course not complete if there are no actual comparison between actual and expected results. This defines whether the check passes or fails, and by default any check will pass if there are no conditions about response failure (except for failure of the test to reach the API endpoint).

    For the example request, this might be one of the ways I want to validate the API response using the nokogiri and rspec gems (assuming that a successful response contains a result element with a count attribute of value 1 inside it):

    def validate_response(response)
       expect(response.xpath(//result).attr('count').to_s).to eq('1'), "Result count should be 1"
    end

    In the end, the implementation of how to properly validate responses vary. There are scenarios where tests need to check for error elements in the response, and there are some tests where data in the response also needs to be verified.