File: unit-testing.md

package info (click to toggle)
strawberry-graphql-django 0.78.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 2,624 kB
  • sloc: python: 31,895; makefile: 24; sh: 21
file content (310 lines) | stat: -rw-r--r-- 7,890 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
---
title: Unit Testing
---

# Unit Testing

Unit testing can be done by following the
[Strawberry's testing docs](https://strawberry.rocks/docs/operations/testing) reference.

This library provides `TestClient` and `AsyncTestClient` that make it easier to run tests by mimicking calls to your GraphQL API with Django's test client.

## Installation

The test clients are included with strawberry-django. No additional installation required.

## TestClient (Sync)

The synchronous test client for testing regular Django views.

### Basic Usage

```python
from strawberry_django.test.client import TestClient


def test_query(db):
    client = TestClient("/graphql")
    response = client.query("""
        query {
            fruits {
                id
                name
            }
        }
    """)
    assert response.errors is None
    assert response.data == {"fruits": [{"id": "1", "name": "Apple"}]}
```

### Constructor

```python
TestClient(path: str, client: Client | None = None)
```

| Parameter | Type             | Description                                                                    |
| --------- | ---------------- | ------------------------------------------------------------------------------ |
| `path`    | `str`            | The URL path to your GraphQL endpoint (e.g., `"/graphql"`)                     |
| `client`  | `Client \| None` | Optional Django test `Client` instance. If not provided, a new one is created. |

### query() Method

```python
client.query(
    query: str,
    variables: dict[str, Any] | None = None,
    headers: dict[str, object] | None = None,
    files: dict[str, object] | None = None,
    assert_no_errors: bool = True,
) -> Response
```

| Parameter          | Type   | Default  | Description                                |
| ------------------ | ------ | -------- | ------------------------------------------ |
| `query`            | `str`  | required | The GraphQL query/mutation string          |
| `variables`        | `dict` | `None`   | Variables to pass to the query             |
| `headers`          | `dict` | `None`   | HTTP headers to include in the request     |
| `files`            | `dict` | `None`   | Files for multipart uploads                |
| `assert_no_errors` | `bool` | `True`   | Automatically assert no errors in response |

### Response Object

The `query()` method returns a `Response` object:

```python
@dataclass
class Response:
    errors: list[GraphQLFormattedError] | None
    data: dict[str, object] | None
    extensions: dict[str, object] | None
```

### Testing with Variables

```python
def test_with_variables(db):
    client = TestClient("/graphql")
    response = client.query(
        """
        query GetFruit($id: ID!) {
            fruit(id: $id) {
                name
            }
        }
        """,
        variables={"id": "1"},
    )
    assert response.data == {"fruit": {"name": "Apple"}}
```

### Testing Mutations

```python
def test_create_fruit(db):
    client = TestClient("/graphql")
    response = client.query(
        """
        mutation CreateFruit($input: FruitInput!) {
            createFruit(input: $input) {
                id
                name
            }
        }
        """,
        variables={"input": {"name": "Banana", "color": "yellow"}},
    )
    assert response.errors is None
    assert response.data["createFruit"]["name"] == "Banana"
```

### Testing with Authentication

Use the `login()` context manager to simulate an authenticated user:

```python
from django.contrib.auth import get_user_model

User = get_user_model()


def test_authenticated_query(db):
    user = User.objects.create_user(username="testuser", password="testpass")
    client = TestClient("/graphql")

    with client.login(user):
        response = client.query("""
            query {
                me {
                    username
                }
            }
        """)

    assert response.errors is None
    assert response.data == {"me": {"username": "testuser"}}
```

### Testing with Custom Headers

```python
def test_with_headers(db):
    client = TestClient("/graphql")
    response = client.query(
        """
        query {
            protectedData
        }
        """,
        headers={"Authorization": "Bearer token123"},
    )
    assert response.errors is None
```

### Testing File Uploads

```python
from django.core.files.uploadedfile import SimpleUploadedFile


def test_file_upload(db):
    client = TestClient("/graphql")
    test_file = SimpleUploadedFile("test.txt", b"file content", content_type="text/plain")

    response = client.query(
        """
        mutation UploadFile($file: Upload!) {
            uploadFile(file: $file) {
                success
            }
        }
        """,
        variables={"file": None},
        files={"file": test_file},
    )
    assert response.errors is None
```

### Expecting Errors

When testing error cases, set `assert_no_errors=False`:

```python
def test_validation_error(db):
    client = TestClient("/graphql")
    response = client.query(
        """
        mutation {
            createFruit(input: {name: ""}) {
                id
            }
        }
        """,
        assert_no_errors=False,
    )
    assert response.errors is not None
    assert "name" in response.errors[0]["message"].lower()
```

## AsyncTestClient

The asynchronous test client for testing async views and ASGI applications.

### Basic Usage

```python
import pytest
from strawberry_django.test.client import AsyncTestClient


@pytest.mark.asyncio
async def test_async_query(db):
    client = AsyncTestClient("/graphql")
    response = await client.query("""
        query {
            fruits {
                id
                name
            }
        }
    """)
    assert response.errors is None
```

### Constructor

```python
AsyncTestClient(path: str, client: AsyncClient | None = None)
```

| Parameter | Type                  | Description                            |
| --------- | --------------------- | -------------------------------------- |
| `path`    | `str`                 | The URL path to your GraphQL endpoint  |
| `client`  | `AsyncClient \| None` | Optional Django `AsyncClient` instance |

### Async Login

```python
@pytest.mark.asyncio
async def test_async_authenticated(db):
    user = await sync_to_async(User.objects.create_user)(
        username="testuser", password="testpass"
    )
    client = AsyncTestClient("/graphql")

    async with client.login(user):
        response = await client.query("""
            query {
                me {
                    username
                }
            }
        """)

    assert response.data == {"me": {"username": "testuser"}}
```

## Using with pytest-django

For pytest-django users, remember to use the `db` fixture:

```python
import pytest


@pytest.mark.django_db
def test_with_database():
    client = TestClient("/graphql")
    # ... your test


@pytest.mark.django_db
@pytest.mark.asyncio
async def test_async_with_database():
    client = AsyncTestClient("/graphql")
    # ... your async test
```

## Using a Custom Django Client

You can pass a pre-configured Django test client:

```python
from django.test import Client


def test_with_custom_client(db):
    django_client = Client(enforce_csrf_checks=True)
    client = TestClient("/graphql", client=django_client)
    # ...
```

## Testing Subscriptions

For testing subscriptions, refer to the [Strawberry WebSocket testing documentation](https://strawberry.rocks/docs/integrations/channels#testing).

## See Also

- [Strawberry Testing Docs](https://strawberry.rocks/docs/operations/testing) - Core testing documentation
- [Django Testing Docs](https://docs.djangoproject.com/en/4.2/topics/testing/) - Django's test framework
- [pytest-django](https://pytest-django.readthedocs.io/) - pytest plugin for Django