FastAPI 教程翻译 - 用户指南 34 - 测试
FastAPI Tutorial - User Guide - Testing
Thanks to Starlette, testing FastAPI applications is easy and enjoyable.
多亏了 Starlette,测试 FastAPI 应用程序变得轻松而愉快。
It is based on Requests, so it’s very familiar and intuitive.
它基于 Requests,因此非常熟悉和直观。
With it, you can use pytest directly with FastAPI.
有了它,您可以直接将 pytest 与 FastAPI 一起使用。
Using TestClient
使用 TestClient
Import
导入
Create a
创建一个
Create functions with a name that starts with
创建名称以
Use the
使用
Write simple
用您需要检查的标准 Python 表达式编写简单的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | from fastapi import FastAPI from fastapi.testclient import TestClient app = FastAPI() @app.get("/") async def read_main(): return {"msg": "Hello World"} client = TestClient(app) def test_read_main(): response = client.get("/") assert response.status_code == 200 assert response.json() == {"msg": "Hello World"} |
Tip
提示
Notice that the testing functions are normal
def , notasync def .请注意,测试功能是正常的
def ,而不是async def 。And the calls to the client are also normal calls, not using
await .并且到客户端的调用也是普通调用,不使用
await 。This allows you to use
pytest directly without complications.这使您可以直接使用
pytest 而不会有任何复杂性。
Technical Details
技术细节
You could also use
from starlette.testclient import TestClient .您也可以使用
from starlette.testclient import TestClient 。FastAPI provides the same
starlette.testclient asfastapi.testclient just as a convenience for you, the developer. But it comes directly from Starlette.FastAPI 提供与
fastapi.testclient 相同的starlette.testclient ,以方便开发人员。但它直接来自 Starlette。
Separating tests
分离测试
In a real application, you probably would have your tests in a different file.
在实际的应用程序中,您可能会将测试放在另一个文件中。
And your FastAPI application might also be composed of several files/modules, etc.
而且您的 FastAPI 应用程序也可能由多个文件 / 模块等组成。
FastAPI app file
FastAPI 应用程序文件
Let’s say you have a file
假设您的 FastAPI 应用有一个文件
1 2 3 4 5 6 7 8 | from fastapi import FastAPI app = FastAPI() @app.get("/") async def read_main(): return {"msg": "Hello World"} |
Testing file
测试文件
Then you could have a file
然后,您可以将带有测试的文件
1 2 3 4 5 6 7 8 9 10 11 | from fastapi.testclient import TestClient from .main import app client = TestClient(app) def test_read_main(): response = client.get("/") assert response.status_code == 200 assert response.json() == {"msg": "Hello World"} |
Testing: extended example
测试:扩展示例
Now let’s extend this example and add more details to see how to test different parts.
现在,让我们扩展该示例并添加更多详细信息,以查看如何测试不同的部分。
Extended FastAPI app file
扩展 FastAPI 应用文件
Let’s say you have a file
假设您的 FastAPI 应用有一个文件
It has a
它具有
It has a
它具有
Both path operations require an
两个路径操作都需要一个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 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 |
Extended testing file
扩展测试文件
You could then have a
然后,您可以使用扩展测试,拥有一个与以前相同的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | from fastapi.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"} |
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
每当您需要客户在请求中传递信息而又不知道如何传递信息时,都可以在
Then you just do the same in your tests.
然后,您只需在测试中执行相同的操作即可。
E.g.:
例如:
-
To pass a path or query parameter, add it to the URL itself.
要传递 path 或 query 参数,请将其添加到 URL 本身。
-
To pass a JSON body, pass a Python object (e.g. a
dict ) to the parameterjson .要传递 JSON 正文,请将 Python 对象(例如
dict )传递给参数json 。 -
If you need to send Form Data instead of JSON, use the
data parameter instead.如果您需要发送表单数据而不是 JSON,请使用
data 参数。 -
To pass headers, use a
dict in theheaders parameter.要传递 headers,请在
headers 参数中使用dict 。 -
For cookies, a
dict in thecookies parameter.对于 cookies,在
cookies 参数中有一个dict 。
For more information about how to pass data to the backend (using
有关如何将数据传递到后端(使用
Info
信息
Note that the
TestClient receives data that can be converted to JSON, not Pydantic models.请注意,
TestClient 接收的数据可以转换为 JSON,而不是 Pydantic 模型。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
jsonable_encoder descibed in JSON Compatible Encoder.如果您的测试中有 Pydantic 模型,并且想在测试过程中将其数据发送到应用程序,则可以使用 JSON 兼容编码器。
Run it
运行
After that, you just need to install
之后,您只需要安装
1 | pip install pytest |
It will detect the files and tests automatically, execute them, and report the results back to you.
它将检测文件并自动进行测试,执行它们,并将结果报告给您。
Run the tests with:
使用以下命令运行测试:
1 | pytest |