mirror of https://github.com/tiangolo/fastapi.git
194 lines
9.9 KiB
Markdown
194 lines
9.9 KiB
Markdown
# Тестирование { #testing }
|
||
|
||
Благодаря <a href="https://www.starlette.dev/testclient/" class="external-link" target="_blank">Starlette</a>, тестировать приложения **FastAPI** легко и приятно.
|
||
|
||
Тестирование основано на библиотеке <a href="https://www.python-httpx.org" class="external-link" target="_blank">HTTPX</a>, которая в свою очередь основана на библиотеке Requests, так что все действия знакомы и интуитивно понятны.
|
||
|
||
Используя эти инструменты, Вы можете напрямую задействовать <a href="https://docs.pytest.org/" class="external-link" target="_blank">pytest</a> с **FastAPI**.
|
||
|
||
## Использование класса `TestClient` { #using-testclient }
|
||
|
||
/// info | Информация
|
||
|
||
Для использования класса `TestClient` сначала установите <a href="https://www.python-httpx.org" class="external-link" target="_blank">`httpx`</a>.
|
||
|
||
Убедитесь, что Вы создали [виртуальное окружение](../virtual-environments.md){.internal-link target=_blank}, активировали его, а затем установили пакет, например:
|
||
|
||
```console
|
||
$ pip install httpx
|
||
```
|
||
|
||
///
|
||
|
||
Импортируйте `TestClient`.
|
||
|
||
Создайте объект `TestClient`, передав ему в качестве параметра Ваше приложение **FastAPI**.
|
||
|
||
Создайте функцию, название которой должно начинаться с `test_` (это стандарт из соглашений `pytest`).
|
||
|
||
Используйте объект `TestClient` так же, как Вы используете `httpx`.
|
||
|
||
Напишите простое утверждение с `assert` дабы проверить истинность Python-выражения (это тоже стандарт `pytest`).
|
||
|
||
{* ../../docs_src/app_testing/tutorial001.py hl[2,12,15:18] *}
|
||
|
||
/// tip | Подсказка
|
||
|
||
Обратите внимание, что тестирующая функция является обычной `def`, а не асинхронной `async def`.
|
||
|
||
И вызов клиента также осуществляется без `await`.
|
||
|
||
Это позволяет вам использовать `pytest` без лишних усложнений.
|
||
|
||
///
|
||
|
||
/// note | Технические детали
|
||
|
||
Также можно написать `from starlette.testclient import TestClient`.
|
||
|
||
**FastAPI** предоставляет тот же самый `starlette.testclient` как `fastapi.testclient`. Это всего лишь небольшое удобство для Вас, как разработчика. Но он берётся напрямую из Starlette.
|
||
|
||
///
|
||
|
||
/// tip | Подсказка
|
||
|
||
Если для тестирования Вам, помимо запросов к приложению FastAPI, необходимо вызывать асинхронные функции (например, для подключения к базе данных с помощью асинхронного драйвера), то ознакомьтесь со страницей [Асинхронное тестирование](../advanced/async-tests.md){.internal-link target=_blank} в расширенном руководстве.
|
||
|
||
///
|
||
|
||
## Разделение тестов { #separating-tests }
|
||
|
||
В реальном приложении Вы, вероятно, разместите тесты в отдельном файле.
|
||
|
||
Кроме того, Ваше приложение **FastAPI** может состоять из нескольких файлов, модулей и т.п.
|
||
|
||
### Файл приложения **FastAPI** { #fastapi-app-file }
|
||
|
||
Допустим, структура файлов Вашего приложения похожа на ту, что описана на странице [Более крупные приложения](bigger-applications.md){.internal-link target=_blank}:
|
||
|
||
```
|
||
.
|
||
├── app
|
||
│ ├── __init__.py
|
||
│ └── main.py
|
||
```
|
||
|
||
В файле `main.py` находится Ваше приложение **FastAPI**:
|
||
|
||
|
||
{* ../../docs_src/app_testing/main.py *}
|
||
|
||
### Файл тестов { #testing-file }
|
||
|
||
Также у Вас может быть файл `test_main.py` содержащий тесты. Можно разместить тестовый файл и файл приложения в одной директории (в директориях для Python-кода желательно размещать и файл `__init__.py`):
|
||
|
||
``` hl_lines="5"
|
||
.
|
||
├── app
|
||
│ ├── __init__.py
|
||
│ ├── main.py
|
||
│ └── test_main.py
|
||
```
|
||
|
||
Так как оба файла находятся в одной директории, для импорта объекта приложения из файла `main` в файл `test_main` Вы можете использовать относительный импорт:
|
||
|
||
{* ../../docs_src/app_testing/test_main.py hl[3] *}
|
||
|
||
|
||
...и писать дальше тесты, как и раньше.
|
||
|
||
## Тестирование: расширенный пример { #testing-extended-example }
|
||
|
||
Теперь давайте расширим наш пример и добавим деталей, чтоб посмотреть, как тестировать различные части приложения.
|
||
|
||
### Расширенный файл приложения **FastAPI** { #extended-fastapi-app-file }
|
||
|
||
Мы продолжим работу с той же файловой структурой, что и ранее:
|
||
|
||
```
|
||
.
|
||
├── app
|
||
│ ├── __init__.py
|
||
│ ├── main.py
|
||
│ └── test_main.py
|
||
```
|
||
|
||
Предположим, что в файле `main.py` с приложением **FastAPI** есть несколько **операций пути**.
|
||
|
||
В нём описана операция `GET`, которая может вернуть ошибку.
|
||
|
||
Ещё есть операция `POST`, и она может вернуть несколько ошибок.
|
||
|
||
Обе *операции пути* требуют наличия в запросе заголовка `X-Token`.
|
||
|
||
{* ../../docs_src/app_testing/app_b_an_py310/main.py *}
|
||
|
||
### Расширенный файл тестов { #extended-testing-file }
|
||
|
||
Теперь обновим файл `test_main.py`, добавив в него тестов:
|
||
|
||
{* ../../docs_src/app_testing/app_b_an_py310/test_main.py *}
|
||
|
||
|
||
Если Вы не знаете, как передать информацию в запросе, можете воспользоваться поисковиком (погуглить) и задать вопрос: "Как передать информацию в запросе с помощью `httpx`", можно даже спросить: "Как передать информацию в запросе с помощью `requests`", поскольку дизайн HTTPX основан на дизайне Requests.
|
||
|
||
Затем Вы просто применяете найденные ответы в тестах.
|
||
|
||
Например:
|
||
|
||
* Передаёте *path*-параметры или *query*-параметры, вписав их непосредственно в строку URL.
|
||
* Передаёте JSON в теле запроса, передав Python-объект (например: `dict`) через именованный параметр `json`.
|
||
* Если же Вам необходимо отправить *форму с данными* вместо JSON, то используйте параметр `data` вместо `json`.
|
||
* Для передачи *заголовков*, передайте объект `dict` через параметр `headers`.
|
||
* Для передачи *cookies* также передайте `dict`, но через параметр `cookies`.
|
||
|
||
Для получения дополнительной информации о передаче данных на бэкенд с помощью `httpx` или `TestClient` ознакомьтесь с <a href="https://www.python-httpx.org" class="external-link" target="_blank">документацией HTTPX</a>.
|
||
|
||
/// info | Информация
|
||
|
||
Обратите внимание, что `TestClient` принимает данные, которые можно конвертировать в JSON, но не модели Pydantic.
|
||
|
||
Если в Ваших тестах есть модели Pydantic и Вы хотите отправить их в тестируемое приложение, то можете использовать функцию `jsonable_encoder`, описанную на странице [Кодировщик совместимый с JSON](encoder.md){.internal-link target=_blank}.
|
||
|
||
///
|
||
|
||
## Запуск { #run-it }
|
||
|
||
Далее Вам нужно установить `pytest`.
|
||
|
||
Убедитесь, что Вы создали [виртуальное окружение](../virtual-environments.md){.internal-link target=_blank}, активировали его, а затем установили пакет, например:
|
||
|
||
<div class="termy">
|
||
|
||
```console
|
||
$ pip install pytest
|
||
|
||
---> 100%
|
||
```
|
||
|
||
</div>
|
||
|
||
Он автоматически найдёт все файлы и тесты, выполнит их и предоставит Вам отчёт о результатах тестирования.
|
||
|
||
Запустите тесты:
|
||
|
||
<div class="termy">
|
||
|
||
```console
|
||
$ 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>
|
||
```
|
||
|
||
</div>
|