REST API Testing In Python

Peter Xie
5 min readJul 11, 2019

--

REST or RESTful API using JSON format has been very popular now because of its simplicity I believe. In this article, I am going to show you how to use Python to create a REST automation test suite using requests and flask packages.

Updates

Part 2: REST API Test Framework for Humans by Plain Text Files
Part 3: Build Dynamic Rest API Mock Service
Part 4: Scale-up REST API functional tests to performance tests in Python

Postman

Firstly, I recommend installing and experimenting with Postman. This tool enables you to create manual test scripts and offers a certain degree of automation (semi-automation) through the utilization of variables and response assertions (limited to Javascript). Notably, it can transform manual scripts into sample code snippets for a wide range of programming languages, Python included. This feature makes it an excellent initial step, particularly for those who are new to API automation.

It is just 4 steps to create a Postman API request test:

  1. Select a request method
  2. Provide the API URL
  3. Add customized headers
  4. Add body

Then just click the Send button to send the request and check the response data.

And you can click the ‘Code’ button to convert the same request to a code snippet of your choice, e.g. Python in this case as shown below. Save the code into a Python file, e.g. postman_code_snippet.py, and run it, and you will get the same response as you run the manual test in Postman.

Postman REST API example
Python code snippet from Postman

Build First Python REST API Test

To build a Python REST API test suite, you will need to install Python3 first, and below packages (using pytest test framework in this example).

pip3 install -U requests Flask pytest pytest-html

Now let’s re-write the above code snippet in a simpler way and convert it to a pytest test as below.

Post API pytest example

As you can see, the Python script also just follows the steps as simple as Postman.

  1. Provide API URL
  2. Add customized headers
    Standard headers like Content-Length are taken care of by requests package.
  3. Add body
    Just create a dictionary variable for your request body, and convert it to json string format using json.dumps() function.
  4. Select a request method
    Use requests.post function for post request, and likewise requests.get for get request, etc.

Note: You can also use json argument in the post method to simplify the code, which automatically sets the Content-Type header to application/json and converts payload in dict to data in string.

url = 'https://httpbin.org/post'
payload = {'key1': 1, 'key2': 'value2'}
resp = requests.post(url, json=payload)

Then we can simply validate the response by checking the response object resp. For example, resp.status_code for response status code, and resp.json() for response body content. Below is the response body print for this post request test, and to validate a field in the response body, e.g. “url”, we can just call assert resp.json()["url"] == "https://httpbin.org/post".

{
"args": {},
"data": "{\n \"key1\": 1,\n \"key2\": \"value2\"\n}",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Content-Length": "39",
"Content-Type": "application/json",
"Host": "httpbin.org",
"User-Agent": "Python Requests"
},
"json": {
"key1": 1,
"key2": "value2"
},
"origin": "103.115.210.48, 103.115.210.48",
"url": "https://httpbin.org/post"
}

Writing tests in Python is so easy and it gives you the power of a programming language to support any flexible needs, e.g. generate a unique transaction id, read test data from a file, or call another dependent API dynamically for an authentication token, etc.

Run with pytest

To run the test with pytest test framework, we need to define the function with test_ prefix and save the file with test_ prefix in the filename, e.g. test_post_headers_body_json.py. Then to run the test, just open a command prompt and type pytest in the script folder, and you will get a test result as follows.

pytest
================ test session starts =======================
platform win32 -- Python 3.7.3, pytest-4.4.1, py-1.8.0, pluggy-0.9.0
rootdir: D:\REST_API_Test_Framework_Python\Scripts\code_snippets
plugins: metadata-1.8.0, html-1.21.1
collected 1 item
test_post_headers_body_json.py . [100%]================= 1 passed in 1.61 seconds ====================

To get more details and generate an HTML report (thanks to pytest-html), run with the below parameters. Check pytest --help for option details.

pytest -sv --html report.html

Logging

When something goes wrong, it is nice to have a full snapshot of every request sent and response received, like the Postman console feature. So we add two pretty print functions as below to print every header, body and status code for request and response. And you can call them by pretty_print_request(resp.request) and pretty_print_response(resp).

Updated script with full logging of request and response
Logging example

Of course, you can write the logging to a file as well, e.g. using the standard logging module, as shown in the repository at the end.

Mocking with Flask

We use Python requests to send requests, and can use Flask to mock server endpoints. So you can perform TDD test development or validate your test code.

For example, below is the code to mock a service endpoint http://127.0.0.1:5000/json and return json format response
{“code”: 1, “message”: “Hello, World!” }.

Mock an HTTP service endpoint

Just save the code as a file, e.g. flask_mock_simple_service.py, and run it by python flask_mock_simple_service.py.

Then you can access this service by typing http://127.0.0.1:5000/json in a browser.

HTTP request from a browser

Or you can write a Python request test code as below.

Test mock service

Less Code with DotMap

In Javascript, you can access dictionary element data in dot fashion as follows.

However, in Python, you have to write person[“name”][“firstname”] instead of person.name.firstname. This is by design in Python to avoid messing up keys and functions/internals (check this reddit topic for more detail).

But as you can see it is handy to write REST/json test code in dot fashion because you write 1 character (.) instead of 4 ([“”]) for each key. IMHO, it is good to use in test code. And we have DotMap package for this purpose.

Install it with pip install dotmap , and you can write your test code like the following.

Put It All Together

To put it together, you can download the full Python REST API test framework repository below, which includes everything mentioned above and more.

Appendix: Python vs JSON Format

Python dictionary looks very like JSON format, but there are still some differences, so you cannot simply put a quote around a dictionary to convert it to JSON string format, though it works most of the time, e.g. ‘{“key1”: “value1”}’ is a valid JSON string format.
Below is data mapping between Python and JSON format. Note that JSON format always uses double quotes for strings.

From https://docs.python.org/

--

--