sanic/guide/content/en/plugins/sanic-testing/clients.md
2023-09-06 15:44:00 +03:00

125 lines
4.2 KiB
Markdown

# Test Clients
There are three different test clients available to you, each of them presents different capabilities.
## Regular sync client: `SanicTestClient`
The `SanicTestClient` runs an actual version of the Sanic Server on your local network to run its tests. Each time it calls an endpoint it will spin up a version of the application and bind it to a socket on the host OS. Then, it will use `httpx` to make calls directly to that application.
This is the typical way that Sanic applications are tested.
.. column::
Once installing Sanic Testing, the regular `SanicTestClient` can be used without further setup. This is because Sanic does the leg work for you under the hood.
.. column::
```python
app.test_client.get("/path/to/endpoint")
```
.. column::
However, you may find it desirable to instantiate the client yourself.
.. column::
```python
from sanic_testing.testing import SanicTestClient
test_client = SanicTestClient(app)
test_client.get("/path/to/endpoint")
```
.. column::
A third option for starting the test client is to use the `TestManager`. This is a convenience object that sets up both the `SanicTestClient` and the `SanicASGITestClient`.
.. column::
```python
from sanic_testing import TestManager
mgr = TestManager(app)
app.test_client.get("/path/to/endpoint")
# or
mgr.test_client.get("/path/to/endpoint")
```
You can make a request by using one of the following methods
- `SanicTestClient.get`
- `SanicTestClient.post`
- `SanicTestClient.put`
- `SanicTestClient.patch`
- `SanicTestClient.delete`
- `SanicTestClient.options`
- `SanicTestClient.head`
- `SanicTestClient.websocket`
- `SanicTestClient.request`
You can use these methods *almost* identically as you would when using `httpx`. Any argument that you would pass to `httpx` will be accepted, **with one caveat**: If you are using `test_client.request` and want to manually specify the HTTP method, you should use: `http_method`:
```python
test_client.request("/path/to/endpoint", http_method="get")
```
## ASGI async client: `SanicASGITestClient`
Unlike the `SanicTestClient` that spins up a server on every request, the `SanicASGITestClient` does not. Instead it makes use of the `httpx` library to execute Sanic as an ASGI application to reach inside and execute the route handlers.
.. column::
This test client provides all of the same methods and generally works as the `SanicTestClient`. The only difference is that you will need to add an `await` to each call:
.. column::
```python
await app.test_client.get("/path/to/endpoint")
```
The `SanicASGITestClient` can be used in the exact same three ways as the `SanicTestClient`.
.. note::
The `SanicASGITestClient` does not need to only be used with ASGI applications. The same way that the `SanicTestClient` does not need to only test sync endpoints. Both of these clients are capable of testing *any* Sanic application.
## Persistent service client: `ReusableClient`
This client works under a similar premise as the `SanicTestClient` in that it stands up an instance of your application and makes real HTTP requests to it. However, unlike the `SanicTestClient`, when using the `ReusableClient` you control the lifecycle of the application.
That means that every request **does not** start a new web server. Instead you will start the server and stop it as needed and can make multiple requests to the same running instance.
.. column::
Unlike the other two clients, you **must** instantiate this client for use:
.. column::
```python
from sanic_testing.reusable import ReusableClient
client = ReusableClient(app)
```
.. column::
Once created, you will use the client inside of a context manager. Once outside of the scope of the manager, the server will shutdown.
.. column::
```python
from sanic_testing.reusable import ReusableClient
def test_multiple_endpoints_on_same_server(app):
client = ReusableClient(app)
with client:
_, response = client.get("/path/to/1")
assert response.status == 200
_, response = client.get("/path/to/2")
assert response.status == 200
```