Testclient
API Reference
starlette.testclient.TestClient
TestClient(app:ASGIApp,base_url:str="http://testserver",raise_server_exceptions:bool=True,root_path:str="",backend:Literal["asyncio","trio"]="asyncio",backend_options:dict[str,Any]|None=None,cookies:CookieTypes|None=None,headers:dict[str,str]|None=None,follow_redirects:bool=True,client:tuple[str,int]=("testclient",50000),)The test client allows you to make requests against your ASGI application,using thehttpx library.
fromstarlette.responsesimportHTMLResponsefromstarlette.testclientimportTestClientasyncdefapp(scope,receive,send):assertscope['type']=='http'response=HTMLResponse('<html><body>Hello, world!</body></html>')awaitresponse(scope,receive,send)deftest_app():client=TestClient(app)response=client.get('/')assertresponse.status_code==200The test client exposes the same interface as any otherhttpx session.In particular, note that the calls to make a request are just standardfunction calls, not awaitables.
You can use any ofhttpx standard API, such as authentication, sessioncookies handling, or file uploads.
For example, to set headers on the TestClient you can do:
client=TestClient(app)# Set headers on the client for future requestsclient.headers={"Authorization":"..."}response=client.get("/")# Set headers for each request separatelyresponse=client.get("/",headers={"Authorization":"..."})And for example to send files with the TestClient:
client=TestClient(app)# Send a single filewithopen("example.txt","rb")asf:response=client.post("/form",files={"file":f})# Send multiple fileswithopen("example.txt","rb")asf1:withopen("example.png","rb")asf2:files={"file1":f1,"file2":("filename",f2,"image/png")}response=client.post("/form",files=files)For more information you can check thehttpxdocumentation.
By default theTestClient will raise any exceptions that occur in theapplication. Occasionally you might want to test the content of 500 errorresponses, rather than allowing client to raise the server exception. In thiscase you should useclient = TestClient(app, raise_server_exceptions=False).
Note
If you want theTestClient to run thelifespan handler,you will need to use theTestClient as a context manager. It willnot be triggered when theTestClient is instantiated. You can learn more about ithere.
Change client address
By default, the TestClient will set the client host to"testserver" and the port to50000.
You can change the client address by setting theclient attribute of theTestClient instance:
client=TestClient(app,client=('localhost',8000))Selecting the Async backend
TestClient takes argumentsbackend (a string) andbackend_options (a dictionary).These options are passed toanyio.start_blocking_portal().See theanyio documentationfor more information about the accepted backend options.By default,asyncio is used with default options.
To runTrio, passbackend="trio". For example:
deftest_app()withTestClient(app,backend="trio")asclient:...To runasyncio withuvloop, passbackend_options={"use_uvloop": True}. For example:
deftest_app()withTestClient(app,backend_options={"use_uvloop":True})asclient:...Testing WebSocket sessions
You can also test websocket sessions with the test client.
Thehttpx library will be used to build the initial handshake, meaning youcan use the same authentication options and other headers between both http andwebsocket testing.
fromstarlette.testclientimportTestClientfromstarlette.websocketsimportWebSocketasyncdefapp(scope,receive,send):assertscope['type']=='websocket'websocket=WebSocket(scope,receive=receive,send=send)awaitwebsocket.accept()awaitwebsocket.send_text('Hello, world!')awaitwebsocket.close()deftest_app():client=TestClient(app)withclient.websocket_connect('/')aswebsocket:data=websocket.receive_text()assertdata=='Hello, world!'The operations on session are standard function calls, not awaitables.
It's important to use the session within a context-managedwith block. Thisensure that the background thread on which the ASGI application is properlyterminated, and that any exceptions that occur within the application arealways raised by the test client.
Establishing a test session
.websocket_connect(url, subprotocols=None, **options)- Takes the same set of arguments ashttpx.get().
May raisestarlette.websockets.WebSocketDisconnect if the application does not accept the websocket connection.
websocket_connect() must be used as a context manager (in awith block).
Note
Theparams argument is not supported bywebsocket_connect. If you need to pass query arguments, hard code itdirectly in the URL.
withclient.websocket_connect('/path?foo=bar')aswebsocket:...Sending data
.send_text(data)- Send the given text to the application..send_bytes(data)- Send the given bytes to the application..send_json(data, mode="text")- Send the given data to the application. Usemode="binary"to send JSON over binary data frames.
Receiving data
.receive_text()- Wait for incoming text sent by the application and return it..receive_bytes()- Wait for incoming bytestring sent by the application and return it..receive_json(mode="text")- Wait for incoming json data sent by the application and return it. Usemode="binary"to receive JSON over binary data frames.
May raisestarlette.websockets.WebSocketDisconnect.
Closing the connection
.close(code=1000)- Perform a client-side close of the websocket connection.
Asynchronous tests
Sometimes you will want to do async things outside of your application.For example, you might want to check the state of your database after calling your appusing your existing async database client/infrastructure.
For these situations, usingTestClient is difficult because it creates it's own event loop and asyncresources (like a database connection) often cannot be shared across event loops.The simplest way to work around this is to just make your entire test async and use an async client, likehttpx.AsyncClient.
Here is an example of such a test:
fromhttpximportAsyncClient,ASGITransportfromstarlette.applicationsimportStarlettefromstarlette.routingimportRoutefromstarlette.requestsimportRequestfromstarlette.responsesimportPlainTextResponsedefhello(request:Request)->PlainTextResponse:returnPlainTextResponse("Hello World!")app=Starlette(routes=[Route("/",hello)])# if you're using pytest, you'll need to to add an async marker like:# @pytest.mark.anyio # using https://github.com/agronholm/anyio# or install and configure pytest-asyncio (https://github.com/pytest-dev/pytest-asyncio)asyncdeftest_app()->None:# note: you _must_ set `base_url` for relative urls like "/" to worktransport=ASGITransport(app=app)asyncwithAsyncClient(transport=transport,base_url="http://testserver")asclient:r=awaitclient.get("/")assertr.status_code==200assertr.text=="Hello World!"