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
.
=== "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.8+"
```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.8+ без Annotated"
!!! tip "Подсказка"
По возможности используйте версию с `Annotated`.
```Python
{!> ../../../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](encoder.md){.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>