Friday, 19 August 2016

API Testing with Robot Framework

This example shows how to start API testing with Robot Framework. Handling of both XML and JSON responses are demonstrated. Example API used is Google Maps Geocoding API and request I make is a location search with a Finnish postal number. My test verifies that the expected city name can be fetched from the response. Robot Framework’s RequestsLibrary is used to make the requests.
Example request:
http://maps.googleapis.com/maps/api/geocode/xml?address=00100,Finland

Write it to browser to get the response. In my test I investigate elements ‘status’ to verity that the response is OK and ‘formatted_address’ to fetch the expected city name, Helsinki in this case.
In case of XML response, Robot Framework’s XML Library is used to parse the response. Method is powerful since xpath expressions can be used to parse the element structure, especially in case of nested or otherwise complex response.
Similar request with JSON response:
http://maps.googleapis.com/maps/api/geocode/json?address=00100,Finland

Name/value pairs at JSON response realise as Python dictionary containing lists and dictionaries in this case. The top level of entries can hence be conveniently accessed e.g. with keyword Get From Dictionary. Parsing more deeply requires either traversing the data structure (like ${response.json()['results'][0]['formatted_address']} in the example), developing parsing functionality in Python or using some of the JSON libraries available. At least straightforward JSON structures can be referred with the existing library implementations but the actual complexity level they can support is another topic.
This was an example how to start API testing with Robot Framework and a few suitable libraries. Powerful cases are already possible without Python coding. Of course, the response as a file, as a string, or as whatever data structure can be parsed in numerous ways depending on the response structure and particular need.

*** Settings ***
Library    RequestsLibrary
Library    XML
Library    String
Library    Collections

Suite Setup    Create Session    googleapi    http://maps.googleapis.com/
Suite Teardown    Delete All Sessions


*** Test Cases ***

Demonstrate API testing and XML response
    Postcode should match city in XML response    00500    Helsinki
    Postcode should match city in XML response    33100    Tampere

Demonstrate API testing and JSON response
    Postcode should match city in JSON response    20250    Turku
    Postcode should match city in JSON response    02200    Espoo



*** Keywords ***
Postcode should match city in XML response
    [Arguments]    ${postal_code}    ${expected_city}

    # Make the request and verify return code
    ${response}=    Get Request     googleapi    maps/api/geocode/xml?address=${postal_code},Finland
    Should Be Equal    ${response.status_code}     ${200}

    # Parse response to XML element structure
    ${xml_response}=    Parse XML    ${response.text}

    # Get and assert element 'status' from the XML structure
    ${status_element}=    Get Element Text    ${xml_response}    status
    Should Be Equal As Strings    ${status_element}    OK

    # Verify that the expected city name can be found from the 'formatted_address' element
    ${returned_address}=     Get Element Text    ${xml_response}     result/formatted_address
    ${returned_city}=    Fetch City From Formatted Address    ${returned_address}

    Should Be Equal As Strings    ${returned_city}    ${expected_city}


Postcode should match city in JSON response
    [Arguments]    ${postal_code}    ${expected_city}

    # Make the request and verify return code
    ${response}=    Get Request     googleapi    maps/api/geocode/json?address=${postal_code},Finland
    Should Be Equal    ${response.status_code}    ${200}

    # Get and assert element 'status' from the JSON dictionary
    ${status_element}=    Get From Dictionary       ${response.json()}    status
    Should Be Equal As Strings    ${status_element}    OK

    # Verify that the expected city name can be found from the 'formatted_address' element
    ${returned_address}=    Set Variable    ${response.json()['results'][0]['formatted_address']}
    ${returned_city}=    Fetch City From Formatted Address    ${returned_address}

    Should Be Equal As Strings    ${returned_city}    ${expected_city}


Fetch City From Formatted Address
    [Arguments]    ${raw_address}
    ${addr}=    Fetch From Left    ${raw_address}    ,
    ${addr}=    Fetch From Right    ${addr}    ${SPACE}
    [Return]    ${addr}