# Python : Web : Starlette : Testing > [!NOTE] > `TestClient` creates its own event loop. If running async tests, consider using `AsyncClient`. ```python from starlette.testclient import TestClient # same API as httpx.Client from httpx import AsyncClient ``` ```python def test_foo(): client = TestClient( app ) response = client.get( "/" ) assert response.status_code == 200 ``` The TestClient will raise any exceptions that occur in the application. If you want to test the content of 500 error responses, rather than allowing client to raise the server exception: ```python client = TestClient( app, raise_server_exceptions=False ) ``` To run asyncio with uvloop: ```python with TestClient( app, backend_options={ "use_uvloop": True } ) as client: ... ``` #### Async > "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 app using your existing async database client / infrastructure. > > For these situations, using `TestClient` is difficult because it creates it's own event loop and async resources (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, like `httpx.AsyncClient`. ([docs](https://www.starlette.io/testclient/#asynchronous-tests)) ```python # assuming pytest-asyncio is installed async def test_app(): async with AsyncClient( transport=httpx.ASGITransport( app=app ), base_url="http://testserver" ) as client: r = await client.get( "/" ) assert r.status_code == 200 assert r.text == "Hello World!" ``` #### Testing WebSocket Sessions It's important to use the session within a context-managed with block. This ensure that the background thread on which the ASGI application is properly terminated, and that any exceptions that occur within the application are always raised by the test client. ```python with client.websocket_connect( "/" ) as websocket: assert websocket.receive_text() == "Hello, world!" ``` `websocket_connect` takes mostly the same args as get() except params. If you need to pass query arguments, hard code it directly in the URL. **Sending & Receiving Data** ```python .send_text( data ) .send_bytes( data ) .send_json( data, mode="text" ) # use mode="binary" to send JSON over binary data frames .receive_text() # wait for incoming text .receive_bytes() # wait for incoming bytestring .receive_json( mode="text" ) # wait for incoming json data # use mode="binary" to receive JSON data over binary data frames ```