# pytest-httpx

> Send responses to httpx.

- **URL**: https://www.freshcrate.ai/projects/pytest-httpx
- **Author**: pypi
- **Category**: Frameworks
- **Latest version**: `0.36.2` (2026-04-21)
- **License**: non-standard
- **Source**: https://github.com/Colin-b/pytest_httpx/blob/master/CHANGELOG.md
- **Homepage**: https://pypi.org/project/pytest-httpx/
- **Language**: Python
- **GitHub**: 445 stars, 37 forks
- **Registry**: pypi (`pytest-httpx`)
- **Tags**: `httpx`, `pypi`, `pytest`, `testing`

## Description

<h2 align="center">Send responses to HTTPX using pytest</h2>

<p align="center">
<a href="https://pypi.org/project/pytest-httpx/"><img alt="pypi version" src="https://img.shields.io/pypi/v/pytest_httpx"></a>
<a href="https://github.com/Colin-b/pytest_httpx/actions"><img alt="Build status" src="https://github.com/Colin-b/pytest_httpx/workflows/Release/badge.svg"></a>
<a href="https://github.com/Colin-b/pytest_httpx/actions"><img alt="Coverage" src="https://img.shields.io/badge/coverage-100%25-brightgreen"></a>
<a href="https://github.com/psf/black"><img alt="Code style: black" src="https://img.shields.io/badge/code%20style-black-000000.svg"></a>
<a href="https://github.com/Colin-b/pytest_httpx/actions"><img alt="Number of tests" src="https://img.shields.io/badge/tests-298 passed-blue"></a>
<a href="https://pypi.org/project/pytest-httpx/"><img alt="Number of downloads" src="https://img.shields.io/pypi/dm/pytest_httpx"></a>
</p>

> [!NOTE]  
> Version 1.0.0 will be released once httpx is considered as stable (release of 1.0.0).
>
> However, current state can be considered as stable.

Once installed, `httpx_mock` [`pytest`](https://docs.pytest.org/en/latest/) fixture will make sure every [`httpx`](https://www.python-httpx.org) request will be replied to with user provided responses ([unless some hosts are explicitly skipped](#do-not-mock-some-requests)).

- [Add responses](#add-responses)
  - [JSON body](#add-json-response)
  - [Custom body](#reply-with-custom-body)
  - [Multipart body (files, ...)](#add-multipart-response)
  - [HTTP status code](#add-non-200-response)
  - [HTTP headers](#reply-with-custom-headers)
  - [HTTP/2.0](#add-http/2.0-response)
- [Add dynamic responses](#dynamic-responses)
- [Raising exceptions](#raising-exceptions)
- [Check requests](#check-sent-requests)
- [Configuration](#configuring-httpx_mock)
  - [Register more responses than requested](#allow-to-register-more-responses-than-what-will-be-requested)
  - [Register less responses than requested](#allow-to-not-register-responses-for-every-request)
  - [Allow to register a response for more than one request](#allow-to-register-a-response-for-more-than-one-request)
  - [Do not mock some requests](#do-not-mock-some-requests)
- [Migrating](#migrating-to-pytest-httpx)
  - [responses](#from-responses)
  - [aioresponses](#from-aioresponses)

## Add responses

You can register responses for both sync and async [`HTTPX`](https://www.python-httpx.org) requests.

```python
import pytest
import httpx


def test_something(httpx_mock):
    httpx_mock.add_response()

    with httpx.Client() as client:
        response = client.get("https://test_url")


@pytest.mark.asyncio
async def test_something_async(httpx_mock):
    httpx_mock.add_response()

    async with httpx.AsyncClient() as client:
        response = await client.get("https://test_url")
```

If all registered responses are not sent back during test execution, the test case will fail at teardown [(unless you turned `assert_all_responses_were_requested` option off)](#allow-to-register-more-responses-than-what-will-be-requested).

Default response is a `HTTP/1.1` `200 (OK)` without any body.

### How response is selected

In case more than one response match request, the first one not yet sent (according to the registration order) will be sent.

In case all matching responses have been sent once, the request will [not be considered as matched](#in-case-no-response-can-be-found) [(unless you turned `can_send_already_matched_responses` option on)](#allow-to-register-a-response-for-more-than-one-request).

You can add criteria so that response will be sent only in case of a more specific matching.

#### Matching on URL

`url` parameter can either be a string, a python [re.Pattern](https://docs.python.org/3/library/re.html) instance or a [httpx.URL](https://www.python-httpx.org/api/#url) instance.

Matching is performed on the full URL, query parameters included.

Order of parameters in the query string does not matter, however order of values do matter if the same parameter is provided more than once.

```python
import httpx
import re
from pytest_httpx import HTTPXMock


def test_url(httpx_mock: HTTPXMock):
    httpx_mock.add_response(url="https://test_url?a=1&b=2")

    with httpx.Client() as client:
        response1 = client.delete("https://test_url?a=1&b=2")
        response2 = client.get("https://test_url?b=2&a=1")


def test_url_as_pattern(httpx_mock: HTTPXMock):
    httpx_mock.add_response(url=re.compile(".*test.*"))

    with httpx.Client() as client:
        response = client.get("https://test_url")


def test_url_as_httpx_url(httpx_mock: HTTPXMock):
    httpx_mock.add_response(url=httpx.URL("https://test_url", params={"a": "1", "b": "2"}))

    with httpx.Client() as client:
        response = client.get("https://test_url?a=1&b=2")
```

##### Ignoring query parameters

Use a python [re.Pattern](https://docs.python.org/3/library/re.html) instance to ignore query parameters while matchi

## Recent releases

| Version | Date | Urgency | Changes |
| --- | --- | --- | --- |
| `0.36.2` | 2026-04-21 | Low | Imported from PyPI (0.36.2) |
| `v0.36.0` | 2025-12-02 | Low | ### Changed - `pytest` required version is now `9`.  ### Added - Explicit support for python `3.14`. - `match_params` parameter is now available on responses and callbacks registration, as well as request(s) retrieval. Allowing to provide query parameters as a dict instead of being part of the matched URL.   - This parameter allows to perform partial query params matching ([refer to documentation](README.md#matching-on-query-parameters) for more information).  ### Fixed - URL with more |
| `v0.35.0` | 2024-11-28 | Low | ### Changed - Requires [`httpx`](https://www.python-httpx.org)==0.28.\* |
| `v0.34.0` | 2024-11-18 | Low | ### Added - `is_optional` parameter is now available on responses and callbacks registration. Allowing to add optional responses while keeping other responses as mandatory. Refer to documentation for more details. - `is_reusable` parameter is now available on responses and callbacks registration. Allowing to add multi-match responses while keeping other responses as single-match. Refer to documentation for more details.  ### Fixed - `httpx_mock.get_request` will now also propose to refine f |
| `v0.33.0` | 2024-10-28 | Low | ### Added - Explicit support for python `3.13`. - `should_mock` option (callable returning a boolean) is now available, defaulting to always returning `True`. Refer to documentation for more details. - Matching on the full multipart body can now be performed using `match_files` and `match_data` parameters. Refer to documentation for more details. - Matching on extensions (including timeout) can now be performed using `match_extensions` parameter. Refer to documentation for more details.  # |
| `v0.32.0` | 2024-09-27 | Low | ### Added - The following option is now available:   - `can_send_already_matched_responses` (boolean), defaulting to `False`. - Assertion failure message in case of unmatched responses is now linking documentation on how to deactivate the check. - Assertion failure message in case of unmatched requests is now linking documentation on how to deactivate the check. - `httpx.TimeoutException` message issued in case of unmatched request is now linking documentation on how to reuse responses (in |
| `v0.31.2` | 2024-09-23 | Low | ### Fixed - `httpx_mock` marker can now be defined at different levels for a single test. |
| `v0.31.1` | 2024-09-22 | Low | ### Fixed - It is now possible to match on content provided as async iterable by the client. |
| `v0.31.0` | 2024-09-20 | Low | ### Changed - Tests will now fail at teardown by default if some requests were issued but were not matched.   - This behavior can be changed thanks to the new ``pytest.mark.httpx_mock(assert_all_requests_were_expected=False)`` option. - The `httpx_mock` fixture is now configured using a marker (many thanks to [`Frazer McLean`](https://github.com/RazerM)).   ```python   # Apply marker to whole module   pytestmark = pytest.mark.httpx_mock(assert_all_responses_were_requested=False)      # O |
| `v0.30.0` | 2024-02-21 | Low | ### Changed - Requires [`httpx`](https://www.python-httpx.org)==0.27.\*  ### Fixed - Switch from `setup.py` to `pyproject.toml` (many thanks to [`Felix Scherz`](https://github.com/felixscherz)). |

## Citation

- HTML: https://www.freshcrate.ai/projects/pytest-httpx
- Markdown: https://www.freshcrate.ai/projects/pytest-httpx.md
- Dependencies JSON: https://www.freshcrate.ai/api/projects/pytest-httpx/deps

_Generated by freshcrate.ai. Indexes pypi releases for AI-agent ecosystem packages._
