File: mocking.md

package info (click to toggle)
python-respx 0.22.0-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 868 kB
  • sloc: python: 4,379; makefile: 17
file content (252 lines) | stat: -rw-r--r-- 6,627 bytes parent folder | download | duplicates (2)
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
!!! attention "Warning"
    This is the documentation of the older version `0.14.0`. See [latest](../../../) for current release.

# Mock HTTPX - Version 0.14.0

To mock out `HTTPX` *and/or* `HTTP Core`, use the `respx.mock` decorator / context manager.

Optionally configure [built-in assertion](api.md#built-in-assertions) checks and [base URL](api.md#base-url)
with `respx.mock(...)`.


## Using the Decorator

``` python
import httpx
import respx


@respx.mock
def test_something():
    request = respx.get("https://foo.bar/", content="foobar")
    response = httpx.get("https://foo.bar/")
    assert request.called
    assert response.status_code == 200
    assert response.text == "foobar"
```


## Using the Context Manager

``` python
import httpx
import respx


with respx.mock:
    request = respx.get("https://foo.bar/", content="foobar")
    response = httpx.get("https://foo.bar/")
    assert request.called
    assert response.status_code == 200
    assert response.text == "foobar"
```

!!! note "NOTE"
    You can also start and stop mocking `HTTPX` manually, by calling `respx.start()` and `respx.stop()`.


## Using the mock Transports

The built-in transports are the base of all mocking and patching in RESPX.

*In fact*, `respx.mock` is an actual instance of `MockTransport`.

### MockTransport
``` python
import httpx
import respx


mock_transport = respx.MockTransport()
request = mock_transport.get("https://foo.bar/", content="foobar")

with mock_transport:
    response = httpx.get("https://foo.bar/")
    assert request.called
    assert response.status_code == 200
    assert response.text == "foobar"
```

### SyncMockTransport

If you don't *need* to patch the original `HTTPX`/`HTTP Core` transports, then use the `SyncMockTransport` or [`AsyncMockTransport`](#asyncmocktransport) directly, by passing the `transport` *arg* when instantiating your `HTTPX` client, or alike.

``` python
import httpx
import respx


mock_transport = respx.SyncMockTransport()
request = mock_transport.get("https://foo.bar/", content="foobar")

with httpx.Client(transport=mock_transport) as client:
    response = client.get("https://foo.bar/")
    assert request.called
    assert response.status_code == 200
    assert response.text == "foobar"
```

### AsyncMockTransport

``` python
import httpx
import respx


mock_transport = respx.AsyncMockTransport()
request = mock_transport.get("https://foo.bar/", content="foobar")

async with httpx.AsyncClient(transport=mock_transport) as client:
    response = await client.get("https://foo.bar/")
    assert request.called
    assert response.status_code == 200
    assert response.text == "foobar"
```

!!! note "NOTE"
    The mock transports takes the same configuration arguments as the decorator / context manager.


## Global Setup & Teardown

### pytest
``` python
# conftest.py
import pytest
import respx


@pytest.fixture
def mocked_api():
    with respx.mock(base_url="https://foo.bar") as respx_mock:
        respx_mock.get("/users/", content=[], alias="list_users")
        ...
        yield respx_mock
```

``` python
# test_api.py
import httpx


def test_list_users(mocked_api):
    response = httpx.get("https://foo.bar/users/")
    request = mocked_api["list_users"]
    assert request.called
    assert response.json() == []
```

!!! tip
    Use a **session** scoped fixture `@pytest.fixture(scope="session")` when your fixture contains **multiple**
    endpoints that not necessary gets called by a single test case, or [disable](api.md#built-in-assertions)
    the built-in `assert_all_called` check.


### unittest

``` python
# testcases.py

class MockedAPIMixin:
    def setUp(self):
        self.mocked_api = respx.mock(base_url="https://foo.bar")
        self.mocked_api.get("/users/", content=[], alias="list_users")
        ...
        self.mocked_api.start()

    def tearDown(self):
        self.mocked_api.stop()
```
``` python
# test_api.py

import unittest
import httpx

from .testcases import MockedAPIMixin


class MyTestCase(MockedAPIMixin, unittest.TestCase):
    def test_list_users(self):
        response = httpx.get("https://foo.bar/users/")
        request = self.mocked_api["list_users"]
        assert request.called
        assert response.json() == []
```

!!! tip
    Use `setUpClass` and `tearDownClass` when you mock **multiple** endpoints that not 
    necessary gets called by a single test method, or [disable](api.md#built-in-assertions)
    the built-in `assert_all_called` check.


## Async Support

You can use `respx.mock` in both **sync** and **async** contexts to mock out `HTTPX` responses.

### pytest
``` python
@respx.mock
@pytest.mark.asyncio
async def test_something():
    async with httpx.AsyncClient() as client:
        request = respx.get("https://foo.bar/", content="foobar")
        response = await client.get("https://foo.bar/")
        assert request.called
        assert response.text == "foobar"
```
``` python
@pytest.mark.asyncio
async def test_something():
    async with respx.mock:
        async with httpx.AsyncClient() as client:
            request = respx.get("https://foo.bar/", content="foobar")
            response = await client.get("https://foo.bar/")
            assert request.called
            assert response.text == "foobar"
```

**Session Scoped Fixtures**

If a session scoped RESPX fixture is used in an async context, you also need to broaden the `pytest-asyncio`
 [event_loop](https://github.com/pytest-dev/pytest-asyncio#event_loop) fixture.
 You can use the `session_event_loop` utility for this. 

``` python
# conftest.py

import pytest
import respx
from respx.fixtures import session_event_loop as event_loop  # noqa: F401


@pytest.fixture(scope="session")
async def mocked_api(event_loop):  # noqa: F811
    async with respx.mock(base_url="https://foo.bar") as respx_mock:
        ...
        yield respx_mock
```

### unittest

``` python
import asynctest


class MyTestCase(asynctest.TestCase):
    @respx.mock
    async def test_something(self):
        async with httpx.AsyncClient() as client:
            request = respx.get("https://foo.bar/", content="foobar")
            response = await client.get("https://foo.bar/")
            assert request.called
            assert response.text == "foobar"

    async def test_something(self):
        async with respx.mock:
            async with httpx.AsyncClient() as client:
                request = respx.get("https://foo.bar/", content="foobar")
                response = await client.get("https://foo.bar/")
                assert request.called
                assert response.text == "foobar"
```