# 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
```