]> git.ipfire.org Git - thirdparty/fastapi/fastapi.git/commitdiff
:white_check_mark: Update testing docs, examples for testing POST, headers (#271)
authorSebastián Ramírez <tiangolo@gmail.com>
Wed, 29 May 2019 07:47:21 +0000 (11:47 +0400)
committerGitHub <noreply@github.com>
Wed, 29 May 2019 07:47:21 +0000 (11:47 +0400)
docs/src/app_testing/main_b.py [new file with mode: 0644]
docs/src/app_testing/test_main_b.py [new file with mode: 0644]
docs/tutorial/testing.md

diff --git a/docs/src/app_testing/main_b.py b/docs/src/app_testing/main_b.py
new file mode 100644 (file)
index 0000000..cb9ced0
--- /dev/null
@@ -0,0 +1,36 @@
+from fastapi import FastAPI, Header, HTTPException
+from pydantic import BaseModel
+
+fake_secret_token = "coneofsilence"
+
+fake_db = {
+    "foo": {"id": "foo", "title": "Foo", "description": "There goes my hero"},
+    "bar": {"id": "bar", "title": "Bar", "description": "The bartenders"},
+}
+
+app = FastAPI()
+
+
+class Item(BaseModel):
+    id: str
+    title: str
+    description: str = None
+
+
+@app.get("/items/{item_id}", response_model=Item)
+async def read_main(item_id: str, x_token: str = Header(...)):
+    if x_token != fake_secret_token:
+        raise HTTPException(status_code=400, detail="Invalid X-Token header")
+    if item_id not in fake_db:
+        raise HTTPException(status_code=404, detail="Item not found")
+    return fake_db[item_id]
+
+
+@app.post("/items/", response_model=Item)
+async def create_item(item: Item, x_token: str = Header(...)):
+    if x_token != fake_secret_token:
+        raise HTTPException(status_code=400, detail="Invalid X-Token header")
+    if item.id in fake_db:
+        raise HTTPException(status_code=400, detail="Item already exists")
+    fake_db[item.id] = item
+    return item
diff --git a/docs/src/app_testing/test_main_b.py b/docs/src/app_testing/test_main_b.py
new file mode 100644 (file)
index 0000000..ad2a2a8
--- /dev/null
@@ -0,0 +1,65 @@
+from starlette.testclient import TestClient
+
+from .main_b import app
+
+client = TestClient(app)
+
+
+def test_read_item():
+    response = client.get("/items/foo", headers={"X-Token": "coneofsilence"})
+    assert response.status_code == 200
+    assert response.json() == {
+        "id": "foo",
+        "title": "Foo",
+        "description": "There goes my hero",
+    }
+
+
+def test_read_item_bad_token():
+    response = client.get("/items/foo", headers={"X-Token": "hailhydra"})
+    assert response.status_code == 400
+    assert response.json() == {"detail": "Invalid X-Token header"}
+
+
+def test_read_inexistent_item():
+    response = client.get("/items/baz", headers={"X-Token": "coneofsilence"})
+    assert response.status_code == 404
+    assert response.json() == {"detail": "Item not found"}
+
+
+def test_create_item():
+    response = client.post(
+        "/items/",
+        headers={"X-Token": "coneofsilence"},
+        json={"id": "foobar", "title": "Foo Bar", "description": "The Foo Barters"},
+    )
+    assert response.status_code == 200
+    assert response.json() == {
+        "id": "foobar",
+        "title": "Foo Bar",
+        "description": "The Foo Barters",
+    }
+
+
+def test_create_item_bad_token():
+    response = client.post(
+        "/items/",
+        headers={"X-Token": "hailhydra"},
+        json={"id": "bazz", "title": "Bazz", "description": "Drop the bazz"},
+    )
+    assert response.status_code == 400
+    assert response.json() == {"detail": "Invalid X-Token header"}
+
+
+def test_create_existing_token():
+    response = client.post(
+        "/items/",
+        headers={"X-Token": "coneofsilence"},
+        json={
+            "id": "foo",
+            "title": "The Foo ID Stealers",
+            "description": "There goes my stealer",
+        },
+    )
+    assert response.status_code == 400
+    assert response.json() == {"detail": "Item already exists"}
index 61352d033a1a6d3eac20340357135c71fa5e66d3..d1be2f09f210d1de1868c32a4064979db63d9f91 100644 (file)
@@ -22,12 +22,11 @@ Write simple `assert` statements with the standard Python expressions that you n
 
 !!! tip
     Notice that the testing functions are normal `def`, not `async def`. 
-    
+
     And the calls to the client are also normal calls, not using `await`.
 
     This allows you to use `pytest` directly without complications.
 
-
 ## Separating tests
 
 In a real application, you probably would have your tests in a different file.
@@ -50,6 +49,51 @@ Then you could have a file `test_main.py` with your tests, and import your `app`
 {!./src/app_testing/test_main.py!}
 ```
 
+## Testing: extended example
+
+Now let's extend this example and add more details to see how to test different parts.
+
+### Extended **FastAPI** app file
+
+Let's say you have a file `main_b.py` with your **FastAPI** app.
+
+It has a `GET` operation that could return an error.
+
+It has a `POST` operation that could return several errors.
+
+Both *path operations* require an `X-Token` header.
+
+```Python
+{!./src/app_testing/main_b.py!}
+```
+
+### Extended testing file
+
+You could then have a `test_main_b.py`, the same as before, with the extended tests:
+
+```Python
+{!./src/app_testing/test_main_b.py!}
+```
+
+Whenever you need the client to pass information in the request and you don't know how to, you can search (Google) how to do it in `requests`.
+
+Then you just do the same in your tests.
+
+E.g.:
+
+* To pass a *path* or *query* parameter, add it to the URL itself.
+* To pass a JSON body, pass a Python object (e.g. a `dict`) to the parameter `json`.
+* If you need to send *Form Data* instead of JSON, use the `data` parameter instead.
+* To pass *headers*, use a `dict` in the `headers` parameter.
+* For *cookies*, a `dict` in the `cookies` parameter.
+
+For more information about how to pass data to the backend (using `requests` or the `TestClient`) check the <a href="http://docs.python-requests.org" target="_blank">Requests documentation</a>.
+
+!!! info
+    Note that the `TestClient` receives data that can be converted to JSON, not Pydantic models.
+
+    If you have a Pydantic model in your test and you want to send its data to the application during testing, you can use the <a href="https://fastapi.tiangolo.com/tutorial/encoder/" target="_blank">JSON compatible encoder: `jsonable_encoder`</a>.
+
 ## Testing WebSockets
 
 You can use the same `TestClient` to test WebSockets.