JavaRush /Курсы /Модуль 4: FastAPI /Тестирование CRUD-операций в FastAPI и Django через SQLAl...

Тестирование CRUD-операций в FastAPI и Django через SQLAlchemy

Модуль 4: FastAPI
6 уровень , 9 лекция
Открыта

Признайтесь, многие считают тестирование скучной рутиной. Но на самом деле это наш надежный щит от катастроф! Представьте, что ваш код — это океанский лайнер, а тесты — команда внимательных инженеров, которые постоянно проверяют, не начал ли он где-то протекать. CRUD-операции находятся в самом сердце любого приложения, и сбои в их работе могут обернуться настоящей катастрофой: от потери важных данных до полного краха бизнес-логики.

Тестирование CRUD-операций становится не просто полезным, а необходимым по нескольким причинам:

  1. Проверка корректности работы API: только с помощью тестов можно быть по-настоящему уверенным, что ваш код правильно выполняет базовые запросы Create, Read, Update, Delete.
  2. Предотвращение багов: ошибки в работе с базой данных особенно коварны — хорошие тесты действуют как страховой полис от самых неприятных сюрпризов.
  3. Спокойствие при расширении: когда вы добавляете новые фичи, работающие тесты дают уверенность, что вы не сломали уже существующий функционал.

Подходы к тестированию

  1. Тестирование на уровне базы данных.
    На этом уровне мы проверяем, что SQLAlchemy выполняет операции с базой данных корректно. Например, что модель сохраняется правильно, данные читаются так, как мы ожидаем, и никакие уникальности или ограничения на уровне базы не нарушаются.
  2. Тестирование API.
    Если ваше приложение предоставляет REST API, то мы тестируем конечные точки (endpoints) приложения — проверяем, как они обрабатывают запросы и возвращают ответы. Это важно для проверки работы приложения "снаружи".
  3. Интеграционное тестирование.
    Такое тестирование охватывает более крупные компоненты системы. Например, вы можете проверить, что вызов конкретного API в FastAPI действительно создает запись в базе через SQLAlchemy.

Написание тестов для CRUD-операций: практика

Давайте разберем, как это всё выглядит в коде! Для этого мы повторно используем наше приложение на FastAPI, которое было создано в предыдущих лекциях.

Перед началом тестирования нужно подготовить тестовое окружение. Мы будем использовать библиотеку Pytest, а для тестирования базы данных создадим специальную тестовую базу.

Установим зависимости для тестов:


pip install pytest pytest-asyncio

Если вы используете PostgreSQL или любую другую СУБД, дополнительно установите драйверы, необходимые для подключения, например:


pip install psycopg2

Пример тестирования CRUD-операций в FastAPI

Для начала создадим самую простую структуру приложения. Пусть это будет API для управления пользователями.

Модель пользователя


from sqlalchemy import Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True, index=True)
    name = Column(String, nullable=False)
    email = Column(String, unique=True, nullable=False)

CRUD-операции

Создадим файл crud.py с основными функциями для взаимодействия с базой.


from sqlalchemy.orm import Session
from .models import User

def create_user(db: Session, name: str, email: str):
    user = User(name=name, email=email)
    db.add(user)
    db.commit()
    db.refresh(user)
    return user

def get_user(db: Session, user_id: int):
    return db.query(User).filter(User.id == user_id).first()

def update_user(db: Session, user_id: int, name: str):
    user = db.query(User).filter(User.id == user_id).first()
    if user:
        user.name = name
        db.commit()
        db.refresh(user)
    return user

def delete_user(db: Session, user_id: int):
    user = db.query(User).filter(User.id == user_id).first()
    if user:
        db.delete(user)
        db.commit()
    return user

Тестирование CRUD операций

Теперь перейдем к тестам. Создадим файл test_crud.py.

Создадим временную базу данных в памяти (SQLite) для обеспечения изоляции тестов.


import pytest
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from ..models import Base

SQLALCHEMY_DATABASE_URL = "sqlite:///:memory:"

engine = create_engine(SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False})
TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

@pytest.fixture(scope="function")
def db():
    Base.metadata.create_all(bind=engine)
    session = TestingSessionLocal()
    try:
        yield session
    finally:
        session.close()

Тесты CREATE и READ. Тестируем создание записи и чтение этой же записи.


from ..crud import create_user, get_user

def test_create_user(db):
    user = create_user(db, name="John Doe", email="john.doe@example.com")
    assert user.id is not None
    assert user.name == "John Doe"
    assert user.email == "john.doe@example.com"

def test_get_user(db):
    user = create_user(db, name="John Doe", email="john.doe@example.com")
    fetched_user = get_user(db, user.id)
    assert fetched_user == user

Тесты UPDATE и DELETE. Обновим имя пользователя и удалим его.


from ..crud import create_user, update_user, delete_user, get_user

def test_update_user(db):
    user = create_user(db, name="John Doe", email="john.doe@example.com")
    updated_user = update_user(db, user.id, name="Jane Doe")
    assert updated_user.name == "Jane Doe"

def test_delete_user(db):
    user = create_user(db, name="John Doe", email="john.doe@example.com")
    delete_user(db, user.id)
    assert get_user(db, user.id) is None

Пример тестирования через API FastAPI

Давайте теперь протестируем API, которое использует эти CRUD-функции.

Для тестирования FastAPI приложений используется стандартный TestClient из библиотеки FastAPI.


from fastapi.testclient import TestClient
from ..main import app

client = TestClient(app)

def test_create_user_api():
    response = client.post("/users/", json={"name": "John Doe", "email": "john.doe@example.com"})
    assert response.status_code == 200
    assert response.json()["name"] == "John Doe"

Тестирование в Django

Если вместо FastAPI вы используете Django, процесс будет выглядеть чуть иначе. Django предоставляет встроенный TestCase для работы с тестами. Вот пример:


from django.test import TestCase
from .models import User

class UserCRUDTests(TestCase):
    def test_create_user(self):
        user = User.objects.create(name="John Doe", email="john.doe@example.com")
        self.assertIsNotNone(user.id)
        self.assertEqual(user.name, "John Doe")
        self.assertEqual(user.email, "john.doe@example.com")

    def test_update_user(self):
        user = User.objects.create(name="John Doe", email="john.doe@example.com")
        user.name = "Jane Doe"
        user.save()
        self.assertEqual(user.name, "Jane Doe")
    
    def test_delete_user(self):
        user = User.objects.create(name="John Doe", email="john.doe@example.com")
        user_id = user.id
        user.delete()
        self.assertFalse(User.objects.filter(id=user_id).exists())

Полезные советы

  • Фикстуры для изоляции: используйте фикстуры Pytest или Django для создания тестовых данных. Это поможет вам избежать нежелательного загрязнения тестовой среды.
  • Mock-тесты: если вы тестируете функции, которые взаимодействуют с внешними API/сервисами, используйте unittest.mock.
  • Интеграция в CI/CD: автоматизируйте запуск тестов в своем CI/CD процессе, чтобы сразу выявлять ошибки.

pytest --cov=your_project/

Теперь вы можете быть уверены, что ваши CRUD операции работают стабильно, независимо от среды и изменений в коде!

1
Задача
Модуль 4: FastAPI, 6 уровень, 9 лекция
Недоступна
Создание тестовой базы данных для CRUD операций
Создание тестовой базы данных для CRUD операций
1
Задача
Модуль 4: FastAPI, 6 уровень, 9 лекция
Недоступна
Тестирование создания и чтения
Тестирование создания и чтения
3
Опрос
Взаимодействие с базой данных через SQLAlchemy в FastAPI, 6 уровень, 9 лекция
Недоступен
Взаимодействие с базой данных через SQLAlchemy в FastAPI
Взаимодействие с базой данных через SQLAlchemy в FastAPI
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ