Robot Framework, REST and JSON with RESTinstance

This is mostly a follow-up of the article Robot Framework, REST and JSON. As this article is now 5 years old, situation has evolved a bit, and recently a new REST library for Robot Framework got some attention: RESTinstance. So let’s take a quick look at it.

Before testing this new lib, let’s rewind a bit. First we need a product to test via a REST API and we will choose one that returns a JSON. For example a GET on http://echo.jsontest.com/framework/robot-framework/api/rest should return:

{
   "api": "rest",
   "framework": "robot-framework"
}

Here is how we checked the response of that endpoint in the previous article using requests library:

*** settings ***
Library  Collections
Library  requests
 
*** test cases ***
simpleRequest
    ${result} =  get  http://echo.jsontest.com/framework/robot-framework/api/rest
    Should Be Equal  ${result.status_code}  ${200}
    ${json} =  Set Variable  ${result.json()}
    ${framework} =  Get From Dictionary  ${json}  framework
    Should Be Equal  ${framework}  robot-framework
    ${api} =  Get From Dictionary  ${json}  api
    Should Be Equal  ${api}  rest

And here is how it can be checked using RESTinstance library:

*** settings ***
Library  REST  http://echo.jsontest.com
 
*** test cases ***
simpleRequest
    GET  /framework/robot-framework/api/rest
    Object  response body
    String  response body api  rest  
    String  response body framework  robot-framework

So when we do a GET, we create a new instance of an object that can then be used by the other keywords of the library. This object can be written on the console log using Output keyword. In my case I get this output:

The current instance as JSON is:
{
    "spec": {},
    "request": {
        "body": null,
        "scheme": "http",
        "sslVerify": true,
        "headers": {
            "Content-Type": "application/json",
            "Accept": "application/json, */*",
            "User-Agent": "RESTinstance/1.0.0b35"
        },
        "allowRedirects": true,
        "timestamp": {
            "utc": "2018-08-15T19:23:04.046254+00:00",
            "local": "2018-08-15T21:23:04.046254+02:00"
        },
        "netloc": "echo.jsontest.com",
        "url": "http://echo.jsontest.com/framework/robot-framework/api/rest",
        "cert": null,
        "timeout": [
            null,
            null
        ],
        "path": "/framework/robot-framework/api/rest",
        "query": {},
        "proxies": {},
        "method": "GET"
    },
    "response": {
        "seconds": 0.173237,
        "status": 200,
        "body": {
            "framework": "robot-framework",
            "api": "rest"
        },
        "headers": {
            "Content-Length": "56",
            "Server": "Google Frontend",
            "X-Cloud-Trace-Context": "8e86c2afa42b5380847247dbdc8a7e24",
            "Date": "Wed, 15 Aug 2018 19:23:03 GMT",
            "Access-Control-Allow-Origin": "*",
            "Content-Type": "application/json; charset=ISO-8859-1"
        }
    },
    "schema": {
        "exampled": true,
        "version": "draft04",
        "request": {
            "body": {
                "type": "null"
            },
            "query": {
                "type": "object"
            }
        },
        "response": {
            "body": {
                "required": [
                    "api",
                    "framework"
                ],
                "type": "object",
                "properties": {
                    "framework": {
                        "enum": [
                            "robot-framework"
                        ],
                        "type": "string",
                        "example": "robot-framework"
                    },
                    "api": {
                        "enum": [
                            "rest"
                        ],
                        "type": "string",
                        "example": "rest"
                    }
                }
            }
        }
    }
}

So when we do String   response body api   rest we are exploring this object and checking the content of [“response”][“body”][“api”] but as we can see there is much more that can be checked. This syntax was a bit unexpected for me but I guess one just has to get used to it.

The library is also quite powerful in terms of JSON schema checking (and generation). I invite you to check the README to explore it further.

Robot Framework, REST and JSON

The software I am testing with Robot Framework offers a REST API as main entry point. So the question arose of what library to use to write my Robot tests.

First one I tried was the robotframework-restlibrary.

  • Pro: it is test-oriented and works well with Robot
  • Con: some features are missing (inspecting returned headers for example) and there is no community/activity around it (no commit since 2009)

I used it for a couple of weeks for my first tests but once I reached the limitations of the library, I quickly looked for another one.

I bumped into 2 others libraries tagged as “REST” and “Robot Framework”

but none of them seemed to be a good fit for me (not much documentation, not the right level of keywords, not very active…). Though, the second one was built on “requests library” which seemed to be worth looking at.

Requests Python Library is not Robot or Test oriented but the feature support is very wide, the use guide is very detailed and the community looks very active.

Here is a simple example of how to use it with Robot Framework:
(we use jstontest.com that sends back a json object when we do a get)

*** settings ***
Library  Collections
Library  requests
*** test cases ***
simpleRequest
    ${result} =  get  http://echo.jsontest.com/framework/robot-framework/api/rest
    Should Be Equal  ${result.status_code}  ${200}
    ${json} =  Set Variable  ${result.json()}
    ${framework} =  Get From Dictionary  ${json}  framework
    Should Be Equal  ${framework}  robot-framework
    ${api} =  Get From Dictionary  ${json}  api
    Should Be Equal  ${api}  rest

The trick then is to create appropriate keywords for often-used command.
For example, to check the value of a property in a one-level json object, we could have this keyword:

json_property_should_equal    
    [Arguments]  ${json}  ${property}  ${value_expected}
    ${value_found} =    Get From Dictionary  ${json}  ${property}
    ${error_message} =  Catenate  SEPARATOR=  Expected value for property "  ${property}  " was "  ${value_expected}  " but found "  ${value_found}  "
    Should Be Equal As Strings  ${value_found}  ${value_expected}  ${error_message}    values=false

I am still looking for a good json lib to create/read/update my json objects.
In the meantime I built a collection of keywords like the one mentioned here.

Hope this help some people facing the same kind of starting point (robot + rest + json).
Ping me if you want some more details.