15 : Unit Testing FastAPI Routes


I was typing this post and it was 90% complete and then I mistakenly closed the tab and lost my work 😭 This time I am using an extension that is autosaving and thus saving me!
So, today we are to discuss unit-testing. Many of you might think that why I did not write a test before actually making the user creation route? It's because I have seen my colleagues struggling with TDD and finally losing interest. Instead, I want to develop your interest in development, Once interested you yourself will follow the best practices.
Is TDD important ? Without a second thought, I would say yes, In our company codebase we have around 1400+ unit tests. Just 2 years before, We were literally fearful each time we had to release a new feature. Because If I make one single change in the Users table, I don't know which part of our codebase may break! I use unit tests mostly for a single purpose. It works as documentation from my side, By designing a unit test I tell fellow developers, how exactly this new feature should work.

Ok enough talk, I don't want to bore you by just talking. So, let's jump into it. We need to create some files and folders:

│ ├─base.py
│ └─version1/
│   ├─route_general_pages.py
│   └─route_users.py
│ ├─config.py
│ └─hashing.py
│ ├─components/
│ │ └─navbar.html
│ ├─general_pages/
│ │ └─homepage.html
│ └─shared/
│   └─base.html
├─tests/            #new
│ ├─conftest.py     #new
│ └─test_routes/    #new
│   └─test_users.py #new

We also need pytest and requests for testing our APIs. So, let's modify our requirements.txt file and do a pip install -r requirements.txt to install these.

#requirements.txt file

#for email validation


#for testing       #new

Now, we will add configurations for testing. Paste the following lines in tests > conftest.py

from typing import Any
from typing import Generator

import pytest
from fastapi import FastAPI
from fastapi.testclient import TestClient
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

import sys
import os
#this is to include backend dir in sys.path so that we can import from db,main.py

from db.base import Base
from db.session import get_db
from apis.base import api_router

def start_application():
    app = FastAPI()
    return app

SQLALCHEMY_DATABASE_URL = "sqlite:///./test_db.db"
engine = create_engine(
    SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}
# Use connect_args parameter only with sqlite
SessionTesting = sessionmaker(autocommit=False, autoflush=False, bind=engine)

def app() -> Generator[FastAPI, Any, None]:
    Create a fresh database on each test case.
    Base.metadata.create_all(engine)  # Create the tables.
    _app = start_application()
    yield _app

def db_session(app: FastAPI) -> Generator[SessionTesting, Any, None]:
    connection = engine.connect()
    transaction = connection.begin()
    session = SessionTesting(bind=connection)
    yield session  # use the session in tests.

def client(
    app: FastAPI, db_session: SessionTesting
) -> Generator[TestClient, Any, None]:
    Create a new FastAPI TestClient that uses the `db_session` fixture to override
    the `get_db` dependency that is injected into routes.

    def _get_test_db():
            yield db_session

    app.dependency_overrides[get_db] = _get_test_db
    with TestClient(app) as client:
        yield client

Now, we can make unit tests, Notice we have made 'client' as a module-level test fixture. So, by using this client we would be able to rollback things and keep our tests isolated and independent. Type the below code in tests > test_routes > test_users.py

import json

def test_create_user(client):
    data = {"username":"testuser","email":"testuser@nofoobar.com","password":"testing"}
    response = client.post("/users/",json.dumps(data))
    assert response.status_code == 200 
    assert response.json()["email"] == "testuser@nofoobar.com"
    assert response.json()["is_active"] == True

Done, now type pytest in the terminal/cmd and see the magic !

Final git commit : Configure unit test settings · nofoobar/JobBoard-Fastapi@b24ffe2 (github.com)

Prev: 14 : Our … Next: 16 : Post …

Brige the gap between Tutorial hell and Industry. We want to bring in the culture of Clean Code, Test Driven Development.

We know, we might make it hard for you but definitely worth the efforts.



Refund Policy

Follow us on our social media channels to stay updated.

© Copyright 2022-23 Team FastAPITutorial