# Тестирование Благодаря Starlette, тестировать приложения **FastAPI** легко и приятно. Тестирование основано на библиотеке HTTPX, которая в свою очередь основана на библиотеке Requests, так что все действия знакомы и интуитивно понятны. Используя эти инструменты, Вы можете напрямую задействовать pytest с **FastAPI**. ## Использование класса `TestClient` !!! info "Информация" Для использования класса `TestClient` необходимо установить библиотеку `httpx`. Например, так: `pip install httpx`. Импортируйте `TestClient`. Создайте объект `TestClient`, передав ему в качестве параметра Ваше приложение **FastAPI**. Создайте функцию, название которой должно начинаться с `test_` (это стандарт из соглашений `pytest`). Используйте объект `TestClient` так же, как Вы используете `httpx`. Напишите простое утверждение с `assert` дабы проверить истинность Python-выражения (это тоже стандарт `pytest`). ```Python hl_lines="2 12 15-18" {!../../../docs_src/app_testing/tutorial001.py!} ``` !!! tip "Подсказка" Обратите внимание, что тестирующая функция является обычной `def`, а не асинхронной `async def`. И вызов клиента также осуществляется без `await`. Это позволяет вам использовать `pytest` без лишних усложнений. !!! note "Технические детали" Также можно написать `from starlette.testclient import TestClient`. **FastAPI** предоставляет тот же самый `starlette.testclient` как `fastapi.testclient`. Это всего лишь небольшое удобство для Вас, как разработчика. !!! tip "Подсказка" Если для тестирования Вам, помимо запросов к приложению FastAPI, необходимо вызывать асинхронные функции (например, для подключения к базе данных с помощью асинхронного драйвера), то ознакомьтесь со страницей [Асинхронное тестирование](../advanced/async-tests.md){.internal-link target=_blank} в расширенном руководстве. ## Разделение тестов и приложения В реальном приложении Вы, вероятно, разместите тесты в отдельном файле. Кроме того, Ваше приложение **FastAPI** может состоять из нескольких файлов, модулей и т.п. ### Файл приложения **FastAPI** Допустим, структура файлов Вашего приложения похожа на ту, что описана на странице [Более крупные приложения](./bigger-applications.md){.internal-link target=_blank}: ``` . ├── app │ ├── __init__.py │ └── main.py ``` Здесь файл `main.py` является "точкой входа" в Ваше приложение и содержит инициализацию Вашего приложения **FastAPI**: ```Python {!../../../docs_src/app_testing/main.py!} ``` ### Файл тестов Также у Вас может быть файл `test_main.py` содержащий тесты. Можно разместить тестовый файл и файл приложения в одной директории (в директориях для Python-кода желательно размещать и файл `__init__.py`): ``` hl_lines="5" . ├── app │ ├── __init__.py │ ├── main.py │ └── test_main.py ``` Так как оба файла находятся в одной директории, для импорта объекта приложения из файла `main` в файл `test_main` Вы можете использовать относительный импорт: ```Python hl_lines="3" {!../../../docs_src/app_testing/test_main.py!} ``` ...и писать дальше тесты, как и раньше. ## Тестирование: расширенный пример Теперь давайте расширим наш пример и добавим деталей, чтоб посмотреть, как тестировать различные части приложения. ### Расширенный файл приложения **FastAPI** Мы продолжим работу с той же файловой структурой, что и ранее: ``` . ├── app │ ├── __init__.py │ ├── main.py │ └── test_main.py ``` Предположим, что в файле `main.py` с приложением **FastAPI** есть несколько **операций пути**. В нём описана операция `GET`, которая может вернуть ошибку. Ещё есть операция `POST` и она тоже может вернуть ошибку. Обе *операции пути* требуют наличия в запросе заголовка `X-Token`. === "Python 3.10+" ```Python {!> ../../../docs_src/app_testing/app_b_an_py310/main.py!} ``` === "Python 3.9+" ```Python {!> ../../../docs_src/app_testing/app_b_an_py39/main.py!} ``` === "Python 3.6+" ```Python {!> ../../../docs_src/app_testing/app_b_an/main.py!} ``` === "Python 3.10+ без Annotated" !!! tip "Подсказка" По возможности используйте версию с `Annotated`. ```Python {!> ../../../docs_src/app_testing/app_b_py310/main.py!} ``` === "Python 3.6+ без Annotated" !!! tip "Подсказка" По возможности используйте версию с `Annotated`. ```Python {!> ../../../docs_src/app_testing/app_b/main.py!} ``` ### Расширенный файл тестов Теперь обновим файл `test_main.py`, добавив в него тестов: ```Python {!> ../../../docs_src/app_testing/app_b/test_main.py!} ``` Если Вы не знаете, как передать информацию в запросе, можете воспользоваться поисковиком (погуглить) и задать вопрос: "Как передать информацию в запросе с помощью `httpx`", можно даже спросить: "Как передать информацию в запросе с помощью `requests`", поскольку дизайн HTTPX основан на дизайне Requests. Затем Вы просто применяете найденные ответы в тестах. Например: * Передаёте *path*-параметры или *query*-параметры, вписав их непосредственно в строку URL. * Передаёте JSON в теле запроса, передав Python-объект (например: `dict`) через именованный параметр `json`. * Если же Вам необходимо отправить *форму с данными* вместо JSON, то используйте параметр `data` вместо `json`. * Для передачи *заголовков*, передайте объект `dict` через параметр `headers`. * Для передачи *cookies* также передайте `dict`, но через параметр `cookies`. Для получения дополнительной информации о передаче данных на бэкенд с помощью `httpx` или `TestClient` ознакомьтесь с документацией HTTPX. !!! info "Информация" Обратите внимание, что `TestClient` принимает данные, которые можно конвертировать в JSON, но не модели Pydantic. Если в Ваших тестах есть модели Pydantic и Вы хотите отправить их в тестируемое приложение, то можете использовать функцию `jsonable_encoder`, описанную на странице [Кодировщик совместимый с JSON](encoder.md){.internal-link target=_blank}. ## Запуск тестов Далее Вам нужно установить `pytest`: