How to Test an API with Pytest and Requests
In previous tutorials, we learned how to build a Full Stack Application with Next.js, FastAPI, and PostgreSQL. In this tutorial, we will learn how to test it with Pytest and Requests.
Writing tests for backend APIs has major benefits. One, they can be used while developing, so instead of manually using a GUI HTTP client to test your API, you can automate it with code. This is helpful when you find yourself repeatedly running a series of requests to test a specific workflow such as user sign up and log in. Second, they can be used to verify the functionality of your API and make sure it is working as expected.
Create nfp-test
directory.
$ mkdir nfp-test
Create virtualenv.
$ python -m venv venv
$ . venv/bin/activate
Install pytest and requests.
$ pip install pytest requests python-dotenv
Create a .env.example
.
API_URL=http://localhost:8000
Create a .env
.
API_URL=http://localhost:8000
Create a .gitignore
.
__pycache__
venv
.pytest_cache
.env
Create a config.py
.
import os
from dotenv import load_dotenv
load_dotenv()
class Config:
API_URL = os.getenv("API_URL")
config = Config()
Create a test_notes.py
.
import requests
from config import config
def test_get_notes():
r = requests.get(f'{config.API_URL}/notes/')
assert r.status_code == 200
def test_post_note():
payload = {"text": "hello world", "completed": False}
r = requests.post(f'{config.API_URL}/notes/', json=payload)
assert r.status_code == 200
Create a test_users.py
.
import requests
import string
import random
from config import config
username = None
password = None
token = None
def test_post_users():
global username
global password
username = ''.join(random.sample(string.ascii_letters, 8))
password = ''.join(random.sample(string.ascii_letters, 8))
payload = {
"username": username,
"password": password
}
r = requests.post(f'{config.API_URL}/users/', json=payload)
assert r.status_code == 200
def test_post_token():
global token
payload = {"username": username, "password": password}
r = requests.post(f'{config.API_URL}/token', data=payload)
json = r.json()
token = json['access_token']
assert r.status_code == 200
def test_get_users_me():
headers = {'Authorization': f'Bearer {token}'}
r = requests.get(f'{config.API_URL}/users/me/', headers=headers)
json = r.json()
assert json['username'] == username
assert r.status_code == 200
def test_get_users_me_items():
headers = {'Authorization': f'Bearer {token}'}
r = requests.get(f'{config.API_URL}/users/me/items/', headers=headers)
assert r.status_code == 200
Run the tests.
$ pytest
Run the tests with stdout for all tests.
$ pytest -rA
Conclusion
Congratulations, you have written the first API tests for our NFP boilerplate app. You have used pytest and requests to test the public endpoints as well as the private endpoints. Even light integration tests such as the ones above will go a long way in increasing developer confidence when making changes to a codebase.