From d4ddcc5878a6cccd9815e76e69ff1fb52bd52457 Mon Sep 17 00:00:00 2001 From: z0z0r4 Date: Sun, 31 Aug 2025 18:29:21 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=9D=20Update=20testing=20events=20docu?= =?UTF-8?q?mentation=20(#13259)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Motov Yurii <109919500+YuriiMotov@users.noreply.github.com> Co-authored-by: Sebastián Ramírez --- docs/en/docs/advanced/testing-events.md | 11 ++++- docs_src/app_testing/tutorial004.py | 43 +++++++++++++++++++ .../test_testing/test_tutorial004.py | 5 +++ 3 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 docs_src/app_testing/tutorial004.py create mode 100644 tests/test_tutorial/test_testing/test_tutorial004.py diff --git a/docs/en/docs/advanced/testing-events.md b/docs/en/docs/advanced/testing-events.md index d0f2d1a79..cb8881a09 100644 --- a/docs/en/docs/advanced/testing-events.md +++ b/docs/en/docs/advanced/testing-events.md @@ -1,5 +1,12 @@ -# Testing Events: startup - shutdown { #testing-events-startup-shutdown } +# Testing Events: lifespan and startup - shutdown { #testing-events-lifespan-and-startup-shutdown } -When you need your event handlers (`startup` and `shutdown`) to run in your tests, you can use the `TestClient` with a `with` statement: +When you need `lifespan` to run in your tests, you can use the `TestClient` with a `with` statement: + +{* ../../docs_src/app_testing/tutorial004.py hl[9:15,18,27:28,30:32,41:43] *} + + +You can read more details about the ["Running lifespan in tests in the official Starlette documentation site."](https://www.starlette.io/lifespan/#running-lifespan-in-tests) + +For the deprecated `startup` and `shutdown` events, you can use the `TestClient` as follows: {* ../../docs_src/app_testing/tutorial003.py hl[9:12,20:24] *} diff --git a/docs_src/app_testing/tutorial004.py b/docs_src/app_testing/tutorial004.py new file mode 100644 index 000000000..f83ac9ae9 --- /dev/null +++ b/docs_src/app_testing/tutorial004.py @@ -0,0 +1,43 @@ +from contextlib import asynccontextmanager + +from fastapi import FastAPI +from fastapi.testclient import TestClient + +items = {} + + +@asynccontextmanager +async def lifespan(app: FastAPI): + items["foo"] = {"name": "Fighters"} + items["bar"] = {"name": "Tenders"} + yield + # clean up items + items.clear() + + +app = FastAPI(lifespan=lifespan) + + +@app.get("/items/{item_id}") +async def read_items(item_id: str): + return items[item_id] + + +def test_read_items(): + # Before the lifespan starts, "items" is still empty + assert items == {} + + with TestClient(app) as client: + # Inside the "with TestClient" block, the lifespan starts and items added + assert items == {"foo": {"name": "Fighters"}, "bar": {"name": "Tenders"}} + + response = client.get("/items/foo") + assert response.status_code == 200 + assert response.json() == {"name": "Fighters"} + + # After the requests is done, the items are still there + assert items == {"foo": {"name": "Fighters"}, "bar": {"name": "Tenders"}} + + # The end of the "with TestClient" block simulates terminating the app, so + # the lifespan ends and items are cleaned up + assert items == {} diff --git a/tests/test_tutorial/test_testing/test_tutorial004.py b/tests/test_tutorial/test_testing/test_tutorial004.py new file mode 100644 index 000000000..812ee44c1 --- /dev/null +++ b/tests/test_tutorial/test_testing/test_tutorial004.py @@ -0,0 +1,5 @@ +from docs_src.app_testing.tutorial004 import test_read_items + + +def test_main(): + test_read_items()