Introduction
If you have been following my last blog on Build A Test Automation Framework with me from Scratch, we will use that framework that we have built to work with our api test. The only different is instead of using Selenium Library we will use Requests Library, and for generating logs and reports are the same.
However we will still start from the beginning, to make you sure we won't get lost.
Get Started
Installation
Python Library required:
pip install pytest
pip install requests
pip install pytest-html
pip install jsonpath
Test Cases
Let's create our first API test cases. Our first test case is to Get list of user from this API endpoint https://reqres.in/api/users?page=2
and verify the response code is 200 ok and page in response body is page number 2.
To do this:
Create a Python Package
testCases
Under
testCases
Package, create a test filetest_GetListUser.py
In
test_GetListUser.py
add the following code:
import json, jsonpath
import requests
baseURL = "https://reqres.in/api/users?page=2"
# Test 01 make sure response code is 200 ok
def test_response_code_200():
# GET request to our api endpoint
response = requests.get(baseURL)
# Check if response code is 200 then passed our test
if response.status_code == 200:
assert True
# if not 200 failed our test
else:
assert False
# Test 02 make sure response page is page number 2
def test_page_number_is_2():
# GET request to our api endpoint
response = requests.get(baseURL)
# Check if response code is 200
if response.status_code == 200:
# get response body in json format
json_response = json.loads(response.text)
# get page param from response body
page = jsonpath.jsonpath(json_response, "page")
# the result will be a list, so use index to compare the result
# check page response is page number 2, then passed our test
if page[0] == 2:
assert True
# otherwise failed our test
else:
assert False
# if status code response with anything beside 200 failed our test
else:
assert False
Run Test Cases
To run our test cases, open terminal or command prompt and change directory to our test cases working directory type the following cmd:
# type pytest following by test filename
pytest test_GetListUser.py
Generate Logs
Let's add logs to our test cases. To Generate Log and add to our test cases:
Create a Python Package
utilities
Create a folder
Log
to store logs from our test casesUnder
utilities
package, create a logger filelogger.py
to generate logsIn
logger.py
add the following code:
import logging
import sys
class LogGen:
@staticmethod
def genlog():
logger = logging.getLogger()
logger.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s | %(levelname)s | %(message)s',
'%m/%d/%Y %I:%M:%S %p')
stdout_handler = logging.StreamHandler(sys.stdout)
stdout_handler.setLevel(logging.DEBUG)
stdout_handler.setFormatter(formatter)
# generate logging and store in logs.log file under log folder
file_handler = logging.FileHandler('../Log/logs.log')
file_handler.setLevel(logging.DEBUG)
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)
logger.addHandler(stdout_handler)
return logger
Add Logs to Test Cases
After we have code to generate logs, let's add logs to our test cases: Don't forget to import logger from utilities package first
import json, jsonpath
import requests
from utilities.logger import LogGen
# GenerateLog Object
generateLog = LogGen.genlog()
baseURL = "https://reqres.in/api/users?page=2"
# Test 01 make sure response code is 200 ok
def test_response_code_200():
generateLog.info("========================= Begin Test Response Code =========================")
# GET request to our api endpoint
generateLog.info("GET Requesting to URL %s", baseURL)
response = requests.get(baseURL)
# Check if response code is 200 then passed our test
if response.status_code == 200:
generateLog.info("Status Code Response %s", response.status_code)
generateLog.info("Response Body: \n %s", json.loads(response.text))
generateLog.info("Test Case PASSED")
generateLog.info("========================= END Test Response Code =========================")
assert True
# if not 200 failed our test
else:
generateLog.warning("Status Code Response %s", response.status_code)
generateLog.error("Test Case FAILED")
generateLog.info("========================= END Test Response Code =========================")
assert False
# Test 02 make sure response page is page number 2
def test_page_number_is_2():
generateLog.info("========================= Begin Test Page Number =========================")
# GET request to our api endpoint
generateLog.info("GET Requesting to URL %s", baseURL)
response = requests.get(baseURL)
# Check if response code is 200
if response.status_code == 200:
generateLog.info("Status Code Response %s", response.status_code)
# get response body in json format
json_response = json.loads(response.text)
generateLog.info("Response Body: \n %s", json_response)
# get page param from response body
page = jsonpath.jsonpath(json_response, "page")
# the result will be a list, so use index to compare the result
# check page response is page number 2, then passed our test
if page[0] == 2:
generateLog.info("Response Page number: %s", page[0])
generateLog.info("Test Case PASSED")
generateLog.info("========================= Begin Test Page Number =========================")
assert True
# otherwise failed our test
else:
generateLog.info("Response Page number: %s", page[0])
generateLog.info("Test Case FAILED")
generateLog.info("========================= END Test Page Number =========================")
assert False
# if status code response with anything beside 200 failed our test
else:
generateLog.info("Status Code Response: %s", response.status_code)
generateLog.info("Test Case FAILED")
generateLog.info("========================= END Test Page Number =========================")
assert False
Run test again, we will get logs in Log/logs.log
file like this:
10/28/2022 01:07:52 PM | INFO | ========================= Begin Test Response Code =========================
10/28/2022 01:07:52 PM | INFO | GET Requesting to URL https://reqres.in/api/users?page=2
10/28/2022 01:07:52 PM | INFO | Status Code Response 200
10/28/2022 01:07:52 PM | INFO | Response Body:
{'page': 2, 'per_page': 6, 'total': 12, 'total_pages': 2, 'data': [{'id': 7, 'email': 'michael.lawson@reqres.in', 'first_name': 'Michael', 'last_name': 'Lawson', 'avatar': 'https://reqres.in/img/faces/7-image.jpg'}, {'id': 8, 'email': 'lindsay.ferguson@reqres.in', 'first_name': 'Lindsay', 'last_name': 'Ferguson', 'avatar': 'https://reqres.in/img/faces/8-image.jpg'}, {'id': 9, 'email': 'tobias.funke@reqres.in', 'first_name': 'Tobias', 'last_name': 'Funke', 'avatar': 'https://reqres.in/img/faces/9-image.jpg'}, {'id': 10, 'email': 'byron.fields@reqres.in', 'first_name': 'Byron', 'last_name': 'Fields', 'avatar': 'https://reqres.in/img/faces/10-image.jpg'}, {'id': 11, 'email': 'george.edwards@reqres.in', 'first_name': 'George', 'last_name': 'Edwards', 'avatar': 'https://reqres.in/img/faces/11-image.jpg'}, {'id': 12, 'email': 'rachel.howell@reqres.in', 'first_name': 'Rachel', 'last_name': 'Howell', 'avatar': 'https://reqres.in/img/faces/12-image.jpg'}], 'support': {'url': 'https://reqres.in/#support-heading', 'text': 'To keep ReqRes free, contributions towards server costs are appreciated!'}}
10/28/2022 01:07:52 PM | INFO | Test Case PASSED
10/28/2022 01:07:52 PM | INFO | ========================= END Test Response Code =========================
10/28/2022 01:07:52 PM | INFO | ========================= Begin Test Page Number =========================
10/28/2022 01:07:52 PM | INFO | GET Requesting to URL https://reqres.in/api/users?page=2
10/28/2022 01:07:52 PM | INFO | Status Code Response 200
10/28/2022 01:07:52 PM | INFO | Response Body:
{'page': 2, 'per_page': 6, 'total': 12, 'total_pages': 2, 'data': [{'id': 7, 'email': 'michael.lawson@reqres.in', 'first_name': 'Michael', 'last_name': 'Lawson', 'avatar': 'https://reqres.in/img/faces/7-image.jpg'}, {'id': 8, 'email': 'lindsay.ferguson@reqres.in', 'first_name': 'Lindsay', 'last_name': 'Ferguson', 'avatar': 'https://reqres.in/img/faces/8-image.jpg'}, {'id': 9, 'email': 'tobias.funke@reqres.in', 'first_name': 'Tobias', 'last_name': 'Funke', 'avatar': 'https://reqres.in/img/faces/9-image.jpg'}, {'id': 10, 'email': 'byron.fields@reqres.in', 'first_name': 'Byron', 'last_name': 'Fields', 'avatar': 'https://reqres.in/img/faces/10-image.jpg'}, {'id': 11, 'email': 'george.edwards@reqres.in', 'first_name': 'George', 'last_name': 'Edwards', 'avatar': 'https://reqres.in/img/faces/11-image.jpg'}, {'id': 12, 'email': 'rachel.howell@reqres.in', 'first_name': 'Rachel', 'last_name': 'Howell', 'avatar': 'https://reqres.in/img/faces/12-image.jpg'}], 'support': {'url': 'https://reqres.in/#support-heading', 'text': 'To keep ReqRes free, contributions towards server costs are appreciated!'}}
10/28/2022 01:07:52 PM | INFO | Response Page number: 2
10/28/2022 01:07:52 PM | INFO | Test Case PASSED
10/28/2022 01:07:52 PM | INFO | ========================= Begin Test Page Number =========================
Generate HTML Report for Test Result
To Generate an HTML Report is so simple, by just run our test cmd with --html
. But let's create a folder Reports
to store our HTML reports then run test with the following command:
# pytest --html=<location you want to store report> follow by test filename
pytest --html=../Reports/report.html test_GetListUser.py
Note: Please refer to the Last blog mentioned at the beginning on how to modified our report.
Test with Other HTTP Method
POST Method
Let's Test Create User with POST request to https://reqres.in/api/users
with request body:
{
"name": "morpheus",
"job": "leader"
}
and verify it response with Status code 201 created
and response body contain id and createdAt
parameter. Create another test test_CreateUser.py
:
import json, jsonpath
import requests
from utilities.logger import LogGen
generateLog = LogGen.genlog()
base_url = 'https://reqres.in/api/users'
def test_create_user_response_code():
generateLog.info("===================== Begin Create User Test =============================")
request_body = {
"name": "morpheus",
"job": "leader"
}
response = requests.post(base_url, request_body)
if response.status_code == 201:
generateLog.info("Status Code Response %s", response.status_code)
json_response = json.loads(response.text)
# check if id and createdAt parameter is returned
if "id" in json_response and "createdAt" in json_response:
generateLog.info("Response body: \n %s", json_response)
generateLog.info("id and createdAt parameter exist in response body")
generateLog.info("Test Case PASSED")
generateLog.info("===================== End Create User Test =============================")
assert True
else:
generateLog.warning("id and createdAt parameter not exist in response body")
generateLog.info("Response body: \n %s", json_response)
generateLog.error("Test Case FAILED")
generateLog.info("===================== End Create User Test =============================")
assert False
else:
generateLog.warning("User failed to created. Status code: %s", response.status_code)
generateLog.info("Response body: \n %s", json.loads(response.text))
generateLog.error("Test Case FAILED")
generateLog.info("===================== End Create User Test =============================")
assert False
PUT Method
Let's Test Update User with PUT request to https://reqres.in/api/users/2
with request body:
{
"name": "morpheus",
"job": "zion resident"
}
and verify it response name with the name in our request body morpheus
and job with the job in our request body zion resident
. Create another test test_UpdateUser.py
:
import json, jsonpath
import requests
from utilities.logger import LogGen
generateLog = LogGen.genlog()
base_url = 'https://reqres.in/api/users/2'
def test_update_user():
generateLog.info("===================== Begin Update User Test =============================")
request_body = {
"name": "morpheus",
"job": "zion resident"
}
response = requests.put(base_url, request_body)
if response.status_code == 200:
generateLog.info("Status Code Response %s", response.status_code)
json_response = json.loads(response.text)
response_name = jsonpath.jsonpath(json_response, "name")
response_job = jsonpath.jsonpath(json_response, "job")
if response_name[0] == request_body["name"] and response_job[0] == request_body["job"]:
generateLog.info("Response body: \n %s", json_response)
generateLog.info("name and job Updated correctly")
generateLog.info("Test Case PASSED")
generateLog.info("===================== End Update User Test =============================")
assert True
else:
generateLog.warning("name and jog does not updated correctly")
generateLog.info("Request body: \n %s", request_body)
generateLog.info("Response body: \n %s", json_response)
generateLog.error("Test Case FAILED")
generateLog.info("===================== End Update User Test =============================")
assert False
else:
generateLog.warning("User failed to update. Status code: %s", response.status_code)
generateLog.info("Response body: \n %s", json.loads(response.text))
generateLog.error("Test Case FAILED")
generateLog.info("===================== End Update User Test =============================")
assert False
PATCH Method
PATCH method do same as PUT, just replace requests.put()
with requests.patch()
instead.
DELETE Method
Let's Test Delete User with DELETE request to https://reqres.in/api/users/2
and verify it response with status code 204
. Create another test test_DeleteUser.py
:
import json, jsonpath
import requests
from utilities.logger import LogGen
generateLog = LogGen.genlog()
base_url = 'https://reqres.in/api/users/2'
def test_delete_user():
generateLog.info("===================== Begin Delete User Test =============================")
response = requests.delete(base_url)
if response.status_code == 204:
generateLog.info("Status Code Response %s", response.status_code)
generateLog.info("User Deleted Successfully")
generateLog.info("Test Case PASSED")
generateLog.info("===================== End Delete User Test =============================")
assert True
else:
generateLog.warning("User failed to Delete. Status code: %s", response.status_code)
generateLog.error("Test Case FAILED")
generateLog.info("===================== End Delete User Test =============================")
assert False
Run all Test Cases with One CMD
Run all test cases under testCases
package with a single command :
pytest --html=../Reports/report.html .
We will have a report.html with all of our test cases:
Conclusion
I would recommend to give a try on my last blog on Build A Test Automation Framework with me from Scratch, it somehow a bit more detail explanation of this Test Framework. However If there is any unclear explanation from me or if I did not explained it properly, feel free to ask me. I will try my best to help with what I could.