10 KiB
Тестирование
Благодаря Starlette, тестировать приложения FastAPI легко и приятно.
Тестирование основано на библиотеке HTTPX, которая в свою очередь основана на библиотеке Requests, так что все действия знакомы и интуитивно понятны.
Используя эти инструменты, Вы можете напрямую задействовать pytest с FastAPI.
Использование класса TestClient
/// info | "Информация"
Для использования класса TestClient необходимо установить библиотеку httpx.
Например, так: pip install httpx.
///
Импортируйте TestClient.
Создайте объект TestClient, передав ему в качестве параметра Ваше приложение FastAPI.
Создайте функцию, название которой должно начинаться с test_ (это стандарт из соглашений pytest).
Используйте объект TestClient так же, как Вы используете httpx.
Напишите простое утверждение с assert дабы проверить истинность Python-выражения (это тоже стандарт pytest).
{!../../../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, необходимо вызывать асинхронные функции (например, для подключения к базе данных с помощью асинхронного драйвера), то ознакомьтесь со страницей Асинхронное тестирование{.internal-link target=_blank} в расширенном руководстве.
///
Разделение тестов и приложения
В реальном приложении Вы, вероятно, разместите тесты в отдельном файле.
Кроме того, Ваше приложение FastAPI может состоять из нескольких файлов, модулей и т.п.
Файл приложения FastAPI
Допустим, структура файлов Вашего приложения похожа на ту, что описана на странице Более крупные приложения{.internal-link target=_blank}:
.
├── app
│ ├── __init__.py
│ └── main.py
Здесь файл main.py является "точкой входа" в Ваше приложение и содержит инициализацию Вашего приложения FastAPI:
{!../../../docs_src/app_testing/main.py!}
Файл тестов
Также у Вас может быть файл test_main.py содержащий тесты. Можно разместить тестовый файл и файл приложения в одной директории (в директориях для Python-кода желательно размещать и файл __init__.py):
.
├── app
│ ├── __init__.py
│ ├── main.py
│ └── test_main.py
Так как оба файла находятся в одной директории, для импорта объекта приложения из файла main в файл test_main Вы можете использовать относительный импорт:
{!../../../docs_src/app_testing/test_main.py!}
...и писать дальше тесты, как и раньше.
Тестирование: расширенный пример
Теперь давайте расширим наш пример и добавим деталей, чтоб посмотреть, как тестировать различные части приложения.
Расширенный файл приложения FastAPI
Мы продолжим работу с той же файловой структурой, что и ранее:
.
├── app
│ ├── __init__.py
│ ├── main.py
│ └── test_main.py
Предположим, что в файле main.py с приложением FastAPI есть несколько операций пути.
В нём описана операция GET, которая может вернуть ошибку.
Ещё есть операция POST и она тоже может вернуть ошибку.
Обе операции пути требуют наличия в запросе заголовка X-Token.
//// tab | Python 3.10+
{!> ../../../docs_src/app_testing/app_b_an_py310/main.py!}
////
//// tab | Python 3.9+
{!> ../../../docs_src/app_testing/app_b_an_py39/main.py!}
////
//// tab | Python 3.8+
{!> ../../../docs_src/app_testing/app_b_an/main.py!}
////
//// tab | Python 3.10+ без Annotated
/// tip | "Подсказка"
По возможности используйте версию с Annotated.
///
{!> ../../../docs_src/app_testing/app_b_py310/main.py!}
////
//// tab | Python 3.8+ без Annotated
/// tip | "Подсказка"
По возможности используйте версию с Annotated.
///
{!> ../../../docs_src/app_testing/app_b/main.py!}
////
Расширенный файл тестов
Теперь обновим файл test_main.py, добавив в него тестов:
{!> ../../../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{.internal-link target=_blank}.
///
Запуск тестов
Далее Вам нужно установить pytest:
$ pip install pytest
---> 100%
Он автоматически найдёт все файлы и тесты, выполнит их и предоставит Вам отчёт о результатах тестирования.
Запустите тесты командой pytest и увидите результат:
$ pytest
================ test session starts ================
platform linux -- Python 3.6.9, pytest-5.3.5, py-1.8.1, pluggy-0.13.1
rootdir: /home/user/code/superawesome-cli/app
plugins: forked-1.1.3, xdist-1.31.0, cov-2.8.1
collected 6 items
---> 100%
test_main.py <span style="color: green; white-space: pre;">...... [100%]</span>
<span style="color: green;">================= 1 passed in 0.03s =================</span>