Browse Source
Co-authored-by: Valentyn Druzhynin <[email protected]> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Rostyslav <[email protected]> Co-authored-by: Sofie Van Landeghem <[email protected]>pull/13432/head
committed by
GitHub
1 changed files with 240 additions and 0 deletions
@ -0,0 +1,240 @@ |
|||
# Тестування |
|||
|
|||
Тестування **FastAPI** додатків є простим та ефективним завдяки бібліотеці <a href="https://www.starlette.io/testclient/" class="external-link" target="_blank">Starlette</a>, яка базується на <a href="https://www.python-httpx.org" class="external-link" target="_blank">HTTPX</a>. |
|||
Оскільки HTTPX розроблений на основі Requests, його API є інтуїтивно зрозумілим для тих, хто вже знайомий з Requests. |
|||
|
|||
З його допомогою Ви можете використовувати <a href="https://docs.pytest.org/" class="external-link" target="_blank">pytest</a> безпосередньо з **FastAPI**. |
|||
|
|||
## Використання `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 | Порада |
|||
|
|||
Якщо Вам потрібно викликати `async`-функції у ваших тестах, окрім відправлення запитів до 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** : |
|||
|
|||
{* ../../docs_src/app_testing/main.py *} |
|||
|
|||
### Файл тестування |
|||
|
|||
Ви можете створити файл `test_main.py` з Вашими тестами. Він може знаходитися в тому ж пакеті Python (у тій самій директорії з файлом `__init__.py`): |
|||
|
|||
|
|||
``` hl_lines="5" |
|||
. |
|||
├── app |
|||
│ ├── __init__.py |
|||
│ ├── main.py |
|||
│ └── test_main.py |
|||
``` |
|||
|
|||
Оскільки цей файл знаходиться в тому ж пакеті, Ви можете використовувати відносний імпорт, щоб імпортувати об'єкт `app` із модуля `main` (`main.py`): |
|||
|
|||
{* ../../docs_src/app_testing/test_main.py hl[3] *} |
|||
|
|||
|
|||
...і написати код для тестів так само як і раніше. |
|||
|
|||
## Тестування: розширений приклад |
|||
|
|||
Тепер розширимо цей приклад і додамо більше деталей, щоб побачити, як тестувати різні частини. |
|||
|
|||
### Розширений файл застосунку **FastAPI** |
|||
|
|||
Залишимо ту саму структуру файлів: |
|||
|
|||
``` |
|||
. |
|||
├── app |
|||
│ ├── __init__.py |
|||
│ ├── main.py |
|||
│ └── test_main.py |
|||
``` |
|||
|
|||
Припустимо, що тепер файл `main.py` із Вашим **FastAPI**-застосунком містить додаткові операції шляху (**path operations**). |
|||
|
|||
Він має `GET`-операцію, яка може повертати помилку. |
|||
|
|||
Він має `POST`-операцію, яка може повертати кілька помилок. |
|||
|
|||
Обидві операції шляху вимагають заголовок `X-Token`. |
|||
|
|||
//// tab | Python 3.10+ |
|||
|
|||
```Python |
|||
{!> ../../docs_src/app_testing/app_b_an_py310/main.py!} |
|||
``` |
|||
|
|||
//// |
|||
|
|||
//// tab | Python 3.9+ |
|||
|
|||
```Python |
|||
{!> ../../docs_src/app_testing/app_b_an_py39/main.py!} |
|||
``` |
|||
|
|||
//// |
|||
|
|||
//// tab | Python 3.8+ |
|||
|
|||
```Python |
|||
{!> ../../docs_src/app_testing/app_b_an/main.py!} |
|||
``` |
|||
|
|||
//// |
|||
|
|||
//// tab | Python 3.10+ non-Annotated |
|||
|
|||
/// tip | Порада |
|||
|
|||
Бажано використовувати версію з `Annotated`, якщо це можливо |
|||
|
|||
/// |
|||
|
|||
```Python |
|||
{!> ../../docs_src/app_testing/app_b_py310/main.py!} |
|||
``` |
|||
|
|||
//// |
|||
|
|||
//// tab | Python 3.8+ non-Annotated |
|||
|
|||
/// tip | Порада |
|||
|
|||
Бажано використовувати версію з `Annotated`, якщо це можливо |
|||
|
|||
/// |
|||
|
|||
```Python |
|||
{!> ../../docs_src/app_testing/app_b/main.py!} |
|||
``` |
|||
|
|||
//// |
|||
|
|||
### Розширений тестовий файл |
|||
|
|||
Потім Ви можете оновити `test_main.py`, додавши розширені тести: |
|||
|
|||
{* ../../docs_src/app_testing/app_b/test_main.py *} |
|||
|
|||
Коли Вам потрібно передати клієнту інформацію в запиті, але Ви не знаєте, як це зробити, Ви можете пошукати (наприклад, у Google) спосіб реалізації в `httpx`, або навіть у `requests`, оскільки HTTPX розроблений на основі дизайну Requests. |
|||
|
|||
Далі Ви просто повторюєте ці ж дії у ваших тестах. |
|||
|
|||
Наприклад: |
|||
|
|||
* Щоб передати *path* або *query* параметр, додайте його безпосередньо до URL. |
|||
* Щоб передати тіло JSON, передайте Python-об'єкт (наприклад, `dict`) у параметр `json`. |
|||
* Якщо потрібно надіслати *Form Data* замість JSON, використовуйте параметр `data`. |
|||
* Щоб передати заголовки *headers*, використовуйте `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 Compatible Encoder](encoder.md){.internal-link target=_blank}. |
|||
|
|||
/// |
|||
|
|||
## Запуск тестів |
|||
|
|||
Після цього вам потрібно встановити `pytest`. |
|||
|
|||
Переконайтеся, що Ви створили [віртуальне середовище]{.internal-link target=_blank}, активували його і встановили необхідні пакети, наприклад: |
|||
|
|||
<div class="termy"> |
|||
|
|||
```console |
|||
$ pip install pytest |
|||
|
|||
---> 100% |
|||
``` |
|||
|
|||
</div> |
|||
|
|||
`pytest` автоматично знайде файли з тестами, виконає їх і надасть вам результати. |
|||
|
|||
Запустіть тести за допомогою: |
|||
|
|||
<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> |
Loading…
Reference in new issue