Tests
Le client de test vous permet d'utiliser la bibliothèque httpx pour faire des requêtes sur votre application ASGI.
from starlette.responses import HTMLResponse
depuis starlette.testclient import TestClient
async def app(scope, receive, send):
assert scope ['type'] == 'http'
response = HTMLResponse(<html><body>Hello, world!</body></html>)
Await Response(scope, receive, send)
def test_app():
Client = TestClient(app)
response = client.get('/')
assert response.status_code == 200
L'interface exposée par le client de test est la même que celle de toute autre session httpx. Notez en particulier que l'appel qui a émis la requête est simplement un appel de fonction standard, pas un objet attendable.
Vous pouvez utiliser n'importe quelle API standard httpx, telle que l'authentification, le traitement des cookies de session ou le téléchargement de fichiers.
Par exemple, pour configurer un en-tête sur TestClient, vous pouvez le faire comme suit:
Client = TestClient(app)
#Définir les têtes sur le client pour les demandes futures
Client.headers = {"Authorization": "..."}
réponse = client.get("/")
#Définir les têtes pour chaque demande séparée
response = client.get("/", headers={"Authorization": "..."})
Par exemple, envoyer un fichier avec TestClient:
Client = TestClient(app)
#Envoyer un fichier unique
avec open("example.txt", "rb") comme f:
response = client.post ("/form", fichiers ={"file": f})
#Envoyer plusieurs fichiers
avec open("example.txt", "rb") comme f1:
avec open("example.png", "rb") comme f2:
fichiers = {"file1": f1, "file2": ("filename", f2, "image/png")}
response = client.post ("/form", files=files)
Pour plus d'informations, vous pouvez consulter la documentation httpx.
Par défaut, TestClient Cela lève toute exception qui se produit dans l'application. occasionnellement, vous pouvez tester le contenu d'une réponse d'erreur 500 plutôt que de permettre au client de lancer une exception serveur. client = TestClient(app, raise_server_exceptions=False) 。
Attention
Si vous voulez le TestClient pour exécuter le lifespan handler,
Vous aurez besoin d'utiliser le TestClient comme un gestionnaire de contexte.
Vous ne pouvez pas en apprendre plus à ce sujet lorsque le TestClient est installé.
ici.
Choisir un backend asynchrone
TestClient accepte les paramètres backend(une chaîne) et backend_options(un dictionnaire). Ces options sont passées à anyio.start_blocking_portal(). voir la documentation anyio pour plus d'informations sur les options de backend acceptables.asyncio et ses options par défaut sont utilisées par défaut.
Désolé, les mots «Trio» et «backend="trio"» dans le texte original ont une signification inconnue et ne peuvent pas être traduits avec précision. si vous pouvez fournir plus d'informations sur les deux symboles, je vais essayer de vous fournir une traduction plus précise.
Def test_app()
Avec TestClient(app, backend="trio") en tant que client:
...
Pour exécuter asyncio avec uvloop, passez backend_options={"use_uvloop": True}.
Def test_app()
avec TestClient(app, backend_options={"use_uvloop": True}) en tant que client:
...
Tester les sessions WebSocket
Vous pouvez également tester une session WebSocket avec un client de test.
httpx La bibliothèque sera utilisée pour construire la poignée de main initiale, ce qui signifie que vous pouvez utiliser les mêmes options d'authentification et d'autres en-têtes entre les tests http et websocket.
depuis starlette.testclient import TestClient
de starlette.websockets import WebSocket
async def app(scope, receive, send):
assert scope ['type'] == 'websocket'
Websocket = WebSocket(scope, receive=receive, send=send)
await websocket.accept()
await websocket.send_text('Hello, world!')
await websocket.close()
def test_app():
client = TestClient(app)
avec client.websocket_connect('/') comme websocket:
data = websocket.receive_text()
assert data =="Hello, world!"
Les opérations sur une session sont des appels de fonction standard, pas des objets attendables.
Il est important d'utiliser des sessions dans des blocs with gérés par contexte. cela garantit que le thread d'arrière-plan dans lequel se trouve l'application ASGI se termine correctement et que toute anomalie survenant dans l'application est toujours levée par le client de test.
Créer une session de test
.websocket_connect(url, subprotocols=None, **options)-prend le même ensemble de paramètres quehttpx.get().
Si l'application n'accepte pas les connexions WebSocket,starlette.websockets.WebSocketDisconnect peut être levé.
websocket_connect() doit être utilisé comme gestionnaire de contexte (dans un bloc with).
!!! Remarque Le paramètre params n'est pas pris en charge par websocket_connect. si vous devez passer un paramètre de requête, codez-le directement dans l'URL.
```python
with client.websocket_connect('/path?foo=bar') as websocket:
...
```
Envoyer les données
.send_text(data)- Envoyer le texte donné à l'application..send_bytes(data)- Envoie l'octet donné à l'application..send_json(data, mode="text")-Envoie les données données à l'application.mode="binary"est utilisé pour envoyer JSON via une trame de données binaire.
Recevoir les données
.receive_text()- Attendez le texte entrant envoyé par l'application et revenez-y..receive_bytes()- Attendez la chaîne d'octets entrante envoyée par l'application et retournez-la..receive_json(mode="text")-Attend les données json entrantes envoyées par l'application et retourne.mode="binary"est utilisé pour recevoir JSON via une trame de données binaires.
Le texte "May raise starlette.websockets.WebSocketDisconnect." ne semble pas correspondre à l'expression sémantique conventionnelle et il est difficile de faire une traduction chinoise précise. Si vous avez plus d'informations contextuelles ou si vous confirmez l'exactitude du contenu du texte, je ferai de mon mieux pour vous fournir une traduction plus satisfaisante. Actuellement, selon une traduction littérale, il ne peut être traduit que par: "peut-être améliorer starlette.websockets.WebSocketDisconnect".
Fermer la connexion.
.close(code=1000)- Effectue l'opération de fermeture de la connexion WebSocket par le client.
Test asynchrone
Parfois, vous souhaiterez effectuer des opérations asynchrones en dehors de l'application-par exemple, vous pouvez vérifier l'état de votre base de données après avoir appelé votre application à l'aide d'un client/infrastructure de base de données asynchrone existant.
Pour ces cas, l'utilisation de TestClient est difficile car elle crée sa propre boucle d'événements et les ressources asynchrones, telles que les connexions de base de données, ne peuvent généralement pas être partagées entre les boucles d'événements. le moyen le plus simple de résoudre ce problème est de rendre vos tests entiers asynchrones et d'utiliser un client asynchrone tel que httpx.AsyncClient.
Voici un exemple d'un tel test:
from httpx import AsyncClient
de starlette.applications import Starlette
de starlette.routing Route d'importation
de starlette.requests Demande d'importation
from starlette.responses import PlainTextResponse
def hello(request: Request) -> PlainTextResponse:
return PlainTextResponse(Hello World!)
app = Starlette(routes=[Route("/", hello)])
#Si vous utilisez Pytest, vous devez ajouter un marqueur async comme:
# @pytest.mark.anyio # using https://github.com/agronholm/anyio
#ou install et configure pytest-asyncio (https://github.com/pytest-dev/pytest-asyncio)
async def test_app() -> None:
# note: vous _Must par_ Set par `base_url` Pour des relations comme "/" au travail
async avec AsyncClient(app=app, base_url="http://testserver") comme client:
r = await client.get("/")
assert r.status_code == 200
assert r.text == "Hello World!"