committed by
GitHub
1 changed files with 212 additions and 0 deletions
@ -0,0 +1,212 @@ |
|||
# Testen |
|||
|
|||
Dank <a href="https://www.starlette.io/testclient/" class="external-link" target="_blank">Starlette</a> ist das Testen von **FastAPI**-Anwendungen einfach und macht Spaß. |
|||
|
|||
Es basiert auf <a href="https://www.python-httpx.org" class="external-link" target="_blank">HTTPX</a>, welches wiederum auf der Grundlage von requests konzipiert wurde, es ist also sehr vertraut und intuitiv. |
|||
|
|||
Damit können Sie <a href="https://docs.pytest.org/" class="external-link" target="_blank">pytest</a> direkt mit **FastAPI** verwenden. |
|||
|
|||
## Verwendung von `TestClient` |
|||
|
|||
!!! info |
|||
Um `TestClient` zu verwenden, installieren Sie zunächst <a href="https://www.python-httpx.org" class="external-link" target="_blank">`httpx`</a>. |
|||
|
|||
Z. B. `pip install httpx`. |
|||
|
|||
Importieren Sie `TestClient`. |
|||
|
|||
Erstellen Sie einen `TestClient`, indem Sie ihm Ihre **FastAPI**-Anwendung übergeben. |
|||
|
|||
Erstellen Sie Funktionen mit einem Namen, der mit `test_` beginnt (das sind `pytest`-Konventionen). |
|||
|
|||
Verwenden Sie das `TestClient`-Objekt auf die gleiche Weise wie `httpx`. |
|||
|
|||
Schreiben Sie einfache `assert`-Anweisungen mit den Standard-Python-Ausdrücken, die Sie überprüfen müssen (wiederum, Standard-`pytest`). |
|||
|
|||
```Python hl_lines="2 12 15-18" |
|||
{!../../../docs_src/app_testing/tutorial001.py!} |
|||
``` |
|||
|
|||
!!! tip "Tipp" |
|||
Beachten Sie, dass die Testfunktionen normal `def` und nicht `async def` sind. |
|||
|
|||
Und die Anrufe an den Client sind ebenfalls normale Anrufe, die nicht `await` verwenden. |
|||
|
|||
Dadurch können Sie `pytest` ohne Komplikationen direkt nutzen. |
|||
|
|||
!!! note "Technische Details" |
|||
Sie könnten auch `from starlette.testclient import TestClient` verwenden. |
|||
|
|||
**FastAPI** stellt denselben `starlette.testclient` auch via `fastapi.testclient` bereit, als Annehmlichkeit für Sie, den Entwickler. Es kommt aber tatsächlich direkt von Starlette. |
|||
|
|||
!!! tip "Tipp" |
|||
Wenn Sie in Ihren Tests neben dem Senden von Anfragen an Ihre FastAPI-Anwendung auch `async`-Funktionen aufrufen möchten (z. B. asynchrone Datenbankfunktionen), werfen Sie einen Blick auf die [Async-Tests](../advanced/async-tests.md){.internal-link target=_blank} im Handbuch für fortgeschrittene Benutzer. |
|||
|
|||
## Tests separieren |
|||
|
|||
In einer echten Anwendung würden Sie Ihre Tests wahrscheinlich in einer anderen Datei haben. |
|||
|
|||
Und Ihre **FastAPI**-Anwendung könnte auch aus mehreren Dateien/Modulen, usw. bestehen. |
|||
|
|||
### **FastAPI** Anwendungsdatei |
|||
|
|||
Nehmen wir an, Sie haben eine Dateistruktur wie in [Größere Anwendungen](bigger-applications.md){.internal-link target=_blank} beschrieben: |
|||
|
|||
``` |
|||
. |
|||
├── app |
|||
│ ├── __init__.py |
|||
│ └── main.py |
|||
``` |
|||
|
|||
In der Datei `main.py` haben Sie Ihre **FastAPI**-Anwendung: |
|||
|
|||
|
|||
```Python |
|||
{!../../../docs_src/app_testing/main.py!} |
|||
``` |
|||
|
|||
### Testdatei |
|||
|
|||
Dann könnten Sie eine Datei `test_main.py` mit Ihren Tests haben. Sie könnte sich im selben Python-Package befinden (dasselbe Verzeichnis mit einer `__init__.py`-Datei): |
|||
|
|||
``` hl_lines="5" |
|||
. |
|||
├── app |
|||
│ ├── __init__.py |
|||
│ ├── main.py |
|||
│ └── test_main.py |
|||
``` |
|||
|
|||
Da sich diese Datei im selben Package befindet, können Sie relative Importe verwenden, um das Objekt `app` aus dem `main`-Modul (`main.py`) zu importieren: |
|||
|
|||
```Python hl_lines="3" |
|||
{!../../../docs_src/app_testing/test_main.py!} |
|||
``` |
|||
|
|||
... und haben den Code für die Tests wie zuvor. |
|||
|
|||
## Testen: erweitertes Beispiel |
|||
|
|||
Nun erweitern wir dieses Beispiel und fügen weitere Details hinzu, um zu sehen, wie verschiedene Teile getestet werden. |
|||
|
|||
### Erweiterte **FastAPI**-Anwendungsdatei |
|||
|
|||
Fahren wir mit der gleichen Dateistruktur wie zuvor fort: |
|||
|
|||
``` |
|||
. |
|||
├── app |
|||
│ ├── __init__.py |
|||
│ ├── main.py |
|||
│ └── test_main.py |
|||
``` |
|||
|
|||
Nehmen wir an, dass die Datei `main.py` mit Ihrer **FastAPI**-Anwendung jetzt einige andere **Pfadoperationen** hat. |
|||
|
|||
Sie verfügt über eine `GET`-Operation, die einen Fehler zurückgeben könnte. |
|||
|
|||
Sie verfügt über eine `POST`-Operation, die mehrere Fehler zurückgeben könnte. |
|||
|
|||
Beide *Pfadoperationen* erfordern einen `X-Token`-Header. |
|||
|
|||
=== "Python 3.10+" |
|||
|
|||
```Python |
|||
{!> ../../../docs_src/app_testing/app_b_an_py310/main.py!} |
|||
``` |
|||
|
|||
=== "Python 3.9+" |
|||
|
|||
```Python |
|||
{!> ../../../docs_src/app_testing/app_b_an_py39/main.py!} |
|||
``` |
|||
|
|||
=== "Python 3.8+" |
|||
|
|||
```Python |
|||
{!> ../../../docs_src/app_testing/app_b_an/main.py!} |
|||
``` |
|||
|
|||
=== "Python 3.10+ nicht annotiert" |
|||
|
|||
!!! tip "Tipp" |
|||
Bevorzugen Sie die `Annotated`-Version, falls möglich. |
|||
|
|||
```Python |
|||
{!> ../../../docs_src/app_testing/app_b_py310/main.py!} |
|||
``` |
|||
|
|||
=== "Python 3.8+ nicht annotiert" |
|||
|
|||
!!! tip "Tipp" |
|||
Bevorzugen Sie die `Annotated`-Version, falls möglich. |
|||
|
|||
```Python |
|||
{!> ../../../docs_src/app_testing/app_b/main.py!} |
|||
``` |
|||
|
|||
### Erweiterte Testdatei |
|||
|
|||
Anschließend könnten Sie `test_main.py` mit den erweiterten Tests aktualisieren: |
|||
|
|||
```Python |
|||
{!> ../../../docs_src/app_testing/app_b/test_main.py!} |
|||
``` |
|||
|
|||
Wenn Sie möchten, dass der Client Informationen im Request übergibt und Sie nicht wissen, wie das geht, können Sie suchen (googeln), wie es mit `httpx` gemacht wird, oder sogar, wie es mit `requests` gemacht wird, da das Design von HTTPX auf dem Design von Requests basiert. |
|||
|
|||
Dann machen Sie in Ihren Tests einfach das gleiche. |
|||
|
|||
Z. B.: |
|||
|
|||
* Um einen *Pfad*- oder *Query*-Parameter zu übergeben, fügen Sie ihn der URL selbst hinzu. |
|||
* Um einen JSON-Body zu übergeben, übergeben Sie ein Python-Objekt (z. B. ein `dict`) an den Parameter `json`. |
|||
* Wenn Sie *Formulardaten* anstelle von JSON senden müssen, verwenden Sie stattdessen den `data`-Parameter. |
|||
* Um *Header* zu übergeben, verwenden Sie ein `dict` im `headers`-Parameter. |
|||
* Für *Cookies* ein `dict` im `cookies`-Parameter. |
|||
|
|||
Weitere Informationen zum Übergeben von Daten an das Backend (mithilfe von `httpx` oder dem `TestClient`) finden Sie in der <a href="https://www.python-httpx.org" class="external-link" target="_blank">HTTPX-Dokumentation</a>. |
|||
|
|||
!!! info |
|||
Beachten Sie, dass der `TestClient` Daten empfängt, die nach JSON konvertiert werden können, keine Pydantic-Modelle. |
|||
|
|||
Wenn Sie ein Pydantic-Modell in Ihrem Test haben und dessen Daten während des Testens an die Anwendung senden möchten, können Sie den `jsonable_encoder` verwenden, der in [JSON-kompatibler Encoder](encoder.md){.internal-link target=_blank} beschrieben wird. |
|||
|
|||
## Tests ausführen |
|||
|
|||
Danach müssen Sie nur noch `pytest` installieren: |
|||
|
|||
<div class="termy"> |
|||
|
|||
```console |
|||
$ pip install pytest |
|||
|
|||
---> 100% |
|||
``` |
|||
|
|||
</div> |
|||
|
|||
Es erkennt die Dateien und Tests automatisch, führt sie aus und berichtet Ihnen die Ergebnisse. |
|||
|
|||
Führen Sie die Tests aus, mit: |
|||
|
|||
<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