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:
- Select a request method
- Provide the API URL
- Add customized headers
- 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.
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.
As you can see, the Python script also just follows the steps as simple as Postman.
- Provide API URL
- Add customized headers
Standard headers like Content-Length are taken care of by requests package. - Add body
Just create a dictionary variable for your request body, and convert it to json string format using json.dumps() function. - 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 itemtest_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)
.
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!” }.
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.
Or you can write a Python request test code as below.
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.