-# 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] *}
--- /dev/null
+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 == {}