Обратите внимание, что тестирующая функция является обычной def, а не асинхронной async def.
И вызов клиента также осуществляется без await.
Это позволяет вам использовать pytest без лишних усложнений.
Технические детали
Также можно написать from starlette.testclient import TestClient.
FastAPI предоставляет тот же самый starlette.testclient как fastapi.testclient. Это всего лишь небольшое удобство для Вас, как разработчика.
Подсказка
Если для тестирования Вам, помимо запросов к приложению FastAPI, необходимо вызывать асинхронные функции (например, для подключения к базе данных с помощью асинхронного драйвера), то ознакомьтесь со страницей Асинхронное тестирование в расширенном руководстве.
Также у Вас может быть файл test_main.py содержащий тесты. Можно разместить тестовый файл и файл приложения в одной директории (в директориях для Python-кода желательно размещать и файл __init__.py):
Так как оба файла находятся в одной директории, для импорта объекта приложения из файла main в файл test_main Вы можете использовать относительный импорт:
Теперь обновим файл test_main.py, добавив в него тестов:
fromfastapi.testclientimportTestClientfrom.mainimportappclient=TestClient(app)deftest_read_item():response=client.get("/items/foo",headers={"X-Token":"coneofsilence"})assertresponse.status_code==200assertresponse.json()=={"id":"foo","title":"Foo","description":"There goes my hero",}deftest_read_item_bad_token():response=client.get("/items/foo",headers={"X-Token":"hailhydra"})assertresponse.status_code==400assertresponse.json()=={"detail":"Invalid X-Token header"}deftest_read_nonexistent_item():response=client.get("/items/baz",headers={"X-Token":"coneofsilence"})assertresponse.status_code==404assertresponse.json()=={"detail":"Item not found"}deftest_create_item():response=client.post("/items/",headers={"X-Token":"coneofsilence"},json={"id":"foobar","title":"Foo Bar","description":"The Foo Barters"},)assertresponse.status_code==200assertresponse.json()=={"id":"foobar","title":"Foo Bar","description":"The Foo Barters",}deftest_create_item_bad_token():response=client.post("/items/",headers={"X-Token":"hailhydra"},json={"id":"bazz","title":"Bazz","description":"Drop the bazz"},)assertresponse.status_code==400assertresponse.json()=={"detail":"Invalid X-Token header"}deftest_create_existing_item():response=client.post("/items/",headers={"X-Token":"coneofsilence"},json={"id":"foo","title":"The Foo ID Stealers","description":"There goes my stealer",},)assertresponse.status_code==409assertresponse.json()=={"detail":"Item already exists"}
Если Вы не знаете, как передать информацию в запросе, можете воспользоваться поисковиком (погуглить) и задать вопрос: "Как передать информацию в запросе с помощью httpx", можно даже спросить: "Как передать информацию в запросе с помощью requests", поскольку дизайн HTTPX основан на дизайне Requests.
Затем Вы просто применяете найденные ответы в тестах.
Например:
Передаёте path-параметры или query-параметры, вписав их непосредственно в строку URL.
Передаёте JSON в теле запроса, передав Python-объект (например: dict) через именованный параметр json.
Если же Вам необходимо отправить форму с данными вместо JSON, то используйте параметр data вместо json.
Для передачи заголовков, передайте объект dict через параметр headers.
Для передачи cookies также передайте dict, но через параметр cookies.
Для получения дополнительной информации о передаче данных на бэкенд с помощью httpx или TestClient ознакомьтесь с документацией HTTPX.
Информация
Обратите внимание, что TestClient принимает данные, которые можно конвертировать в JSON, но не модели Pydantic.
Если в Ваших тестах есть модели Pydantic и Вы хотите отправить их в тестируемое приложение, то можете использовать функцию jsonable_encoder, описанную на странице Кодировщик совместимый с JSON.