Skip to content

Manual testing

Iván de Paz Centeno edited this page Dec 19, 2017 · 3 revisions

When dealing with the creation of a REST API, sometimes it is wanted to test whether a certain API method is working or not. In this page it is summarized two useful ways of manually testing the solution and, at the end, a way to implement this as unit tests for your project.

Testing with cURL/Requests

cURL is a wonderful CLI tool that is powerful enough to test any REST API endpoint. requests is a wonderful Python package that is really simple and at the same time powerful enough to test any REST API endpoint. It requires to be installed pip3 install requests.

Testing simple REST API.

Suppose that we run a program like the following:

from flasked import Flasked
from flask import request

class Root():
    def get(self):
        content = request.get_json()
        return "Get invoked!; Content is {}".format(content)

    def post(self):
        content = request.get_json()
        return "Post invoked!; Content is {}".format(content)

app = Flasked()
app["/"] = Root
app.run(host="localhost", port=1025)

A way to test whether the get and post methods are working:

In cURL

> curl -X GET "http://localhost:1025"
"Get invoked!; Content is None"
> curl -X POST "http://localhost:1025"
"Post invoked!; Content is None"

The -X flag allows you to set the HTTP method to call.

In requests

>>> import requests
>>> response = requests.get("http://localhost:1025")
>>> print(response.text)
"Get invoked!; Content is None"

>>> response = requests.post("http://localhost:1025")
>>> print(response.text)
"Post invoked!; Content is None"

Note: The advantage with requests is that it is able to retrieve JSON directly, into a Python's Dict, by using the method response.json().

If we want to send a JSON content:

In cURL

> curl -X GET -H "Content-Type: application/json" -d '{"name": "Ivan"}' "http://localhost:1025" 
"Get invoked!; Content is {'name': 'Ivan'}"
> curl -X POST -H "Content-Type: application/json" -d '{"name": "Ivan"}' "http://localhost:1025"
"Post invoked!; Content is {'name': 'Ivan'}"

The -H flag allows to set headers for the request. For sending a JSON it is required to set the MIME-type to application/json.

The -d flag allows to set the content of the request body. Here is where the JSON content goes.

In requests

>>> import requests
>>> response = requests.get("http://localhost:1025", json={'name':'Ivan'})
>>> print(response.text)
"Get invoked!; Content is {'name': 'Ivan'}"

>>> response = requests.post("http://localhost:1025", json={'name':'Ivan'})
>>> print(response.text)
"Post invoked!; Content is {'name': 'Ivan'}"

Testing REST API with files.

Sometimes it is required to send/retrieve files to/from REST API endpoints. Suppose we have the following API:

from flasked import Flasked
from flask import request, send_file
from io import BytesIO

stored_files = {}

class Root():
    def get(self):
        file_id = request.args['fileid']
        return send_file(BytesIO(stored_files[file_id]), mimetype="application/octet-stream")

    def post(self):
        file_id = request.args['fileid']
        content = request.stream.read()
        stored_files[file_id] = content
        return "File stored with id {}, content of file size was {} KB".format(file_id, round(len(content) / 1024, 2))

app = Flasked()
app["/"] = Root
app.run(host="localhost", port=1025)

This example is expecting an argument named fileid and a certain content in binary format (MIME-Type application/octet-stream). In cURL, this REST API can be used in the following way:

** In cURL **

> curl -X POST -H "Content-Type: application/octet-stream" --data-binary "Binary Data!!" "http://localhost:1025/?fileid=1"
"File stored with id 1, content of file size was 0.01 KB"

> curl -X GET "http://localhost:1025/?fileid=1"
Binary Data!!

The flag --data-binary can hold any binary content. However, sometimes it is wanted to send the content of a file. This can be accomplished using the @ operator:

> curl -X POST -H "Content-Type: application/octet-stream" --data-binary @"/path/to/file.jpg" "http://localhost:1025/?fileid=CUSTOM"
"File stored with id CUSTOM, content of file size was 23.51 KB"

In requests

>>> import requests
>>> response = requests.post("http://localhost:1025", params={'fileid': 1}, data=b"Binary data!!")
>>> print(response.text)
"File stored with id 1, content of file size was 0.01 KB"

>>> response = requests.get("http://localhost:1025", params={'fileid':'1'})
>>> print(response.content)
b"Binary data!!"

Clone this wiki locally