Какими классами описал бы CRUD при тестировании API?

«Какими классами описал бы CRUD при тестировании API?» — вопрос из категории API тестирование, который задают на 24% собеседований AQA / Automation. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

При проектировании фреймворка для тестирования CRUD API я бы выделил следующие логические классы или модули:

  1. BaseAPIClient / BaseTestClass: Базовый класс для инкапсуляции общей логики: инициализация HTTP-клиента (с сессией, заголовками по умолчанию), обработка аутентификации (получение и подстановка токена), базовые методы для отправки запросов и логирования.
  2. TestDataFactory: Отдельный класс или модуль для генерации тестовых данных (валидных и невалидных). Это позволяет легко переиспользовать данные и поддерживать их консистентность.
  3. Модули с тестами, сгруппированные по операциям:
    • test_create.py – тесты на создание сущности (POST). Проверяют коды ответа 201, корректность возвращенных данных, наличие обязательных полей.
    • test_read.py – тесты на чтение (GET, GET список). Проверяют получение одной сущности, пагинацию, фильтрацию, сортировку.
    • test_update.py – тесты на обновление (PUT, PATCH). Проверяют полное и частичное обновление, валидацию.
    • test_delete.py – тесты на удаление (DELETE). Проверяют код 204 или 200, последующую недоступность ресурса.

Пример структуры теста:

# test_users.py
import pytest

class TestUsersCRUD:

    def test_create_user(self, api_client, user_data):
        """POST /users"""
        response = api_client.post("/users", json=user_data)
        assert response.status_code == 201
        created_user = response.json()
        assert created_user["name"] == user_data["name"]
        assert "id" in created_user
        return created_user["id"]  # Можно использовать в других тестах

    @pytest.mark.parametrize("user_id, expected_code", [
        ("invalid_id", 404),
        (999999, 404)
    ])
    def test_get_user_negative(self, api_client, user_id, expected_code):
        """GET /users/{id} - негативные сценарии"""
        response = api_client.get(f"/users/{user_id}")
        assert response.status_code == expected_code

Дополнительно я бы выделил conftest.py для общих фикстур (например, @pytest.fixture для предсоздания и последующего удаления тестового пользователя) и отдельный модуль для тестов, связанных с бизнес-логикой, а не просто CRUD.