Observe que as funções de teste são def normais, não async def.
E as chamadas para o cliente também são chamadas normais, não usando await.
Isso permite que você use pytest diretamente sem complicações.
Detalhes técnicos
Você também pode usar from starlette.testclient import TestClient.
FastAPI fornece o mesmo starlette.testclient que fastapi.testclient apenas como uma conveniência para você, o desenvolvedor. Mas ele vem diretamente da Starlette.
Dica
Se você quiser chamar funções async em seus testes além de enviar solicitações ao seu aplicativo FastAPI (por exemplo, funções de banco de dados assíncronas), dê uma olhada em Testes assíncronos no tutorial avançado.
Então você poderia ter um arquivo test_main.py com seus testes. Ele poderia estar no mesmo pacote Python (o mesmo diretório com um arquivo __init__.py):
Você pode então atualizar test_main.py com os testes estendidos:
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"}
Sempre que você precisar que o cliente passe informações na requisição e não souber como, você pode pesquisar (no Google) como fazer isso no httpx, ou até mesmo como fazer isso com requests, já que o design do HTTPX é baseado no design do Requests.
Depois é só fazer o mesmo nos seus testes.
Por exemplo:
Para passar um parâmetro path ou query, adicione-o à própria URL.
Para passar um corpo JSON, passe um objeto Python (por exemplo, um dict) para o parâmetro json.
Se você precisar enviar Dados de Formulário em vez de JSON, use o parâmetro data.
Para passar headers, use um dict no parâmetro headers.
Para cookies, um dict no parâmetro cookies.
Para mais informações sobre como passar dados para o backend (usando httpx ou TestClient), consulte a documentação do HTTPX.
Informação
Observe que o TestClient recebe dados que podem ser convertidos para JSON, não para modelos Pydantic.
Se você tiver um modelo Pydantic em seu teste e quiser enviar seus dados para o aplicativo durante o teste, poderá usar o jsonable_encoder descrito em Codificador compatível com JSON.