Give AlbumentationsX a star on GitHub — it powers this leaderboard

Star on GitHub

pytest-httpx

Send responses to httpx.

Rank: #1695Downloads: 5,341,197 (30 days)

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-295 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 fixture will make sure every httpx request will be replied to with user provided responses (unless some hosts are explicitly skipped).

Add responses

You can register responses for both sync and async HTTPX requests.

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).

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 (unless you turned can_send_already_matched_responses option on).

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 instance or a httpx.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.

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")

Matching on query parameters

Use match_params to partially match query parameters without having to provide a regular expression as url.

If this parameter is provided, url parameter must not contain any query parameter.

All query parameters have to be provided (as str). You can however use unittest.mock.ANY to do partial matching.

import httpx
from pytest_httpx import HTTPXMock
from unittest.mock import ANY

def test_partial_params_matching(httpx_mock: HTTPXMock):
    httpx_mock.add_response(url="https://test_url", match_params={"a": "1", "b": ANY})

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

def test_partial_multi_params_matching(httpx_mock: HTTPXMock):
    httpx_mock.add_response(url="https://test_url", match_params={"a": ["1", "3"], "b": ["2", ANY]})

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

Matching on HTTP method

Use method parameter to specify the HTTP method (POST, PUT, DELETE, PATCH, HEAD) to reply to.

method parameter must be a string. It will be upper-cased, so it can be provided lower cased.

Matching is performed on equality.

import httpx
from pytest_httpx import HTTPXMock


def test_post(httpx_mock: HTTPXMock):
    httpx_mock.add_response(method="POST")

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


def test_put(httpx_mock: HTTPXMock):
    httpx_mock.add_response(method="PUT")

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


def test_delete(httpx_mock: HTTPXMock):
    httpx_mock.add_response(method="DELETE")

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


def test_patch(httpx_mock: HTTPXMock):
    httpx_mock.add_response(method="PATCH")

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


def test_head(httpx_mock: HTTPXMock):
    httpx_mock.add_response(method="HEAD")

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

Matching on proxy URL

proxy_url parameter can either be a string, a python re.Pattern instance or a httpx.URL instance.

Matching is performed on the full proxy 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.

import httpx
from pytest_httpx import HTTPXMock


def test_proxy_url(httpx_mock: HTTPXMock):
    httpx_mock.add_response(proxy_url="http://test_proxy_url?b=1&a=2")

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

Matching on HTTP headers

Use match_headers parameter to specify the HTTP headers (as a dict) to reply to.

Matching is performed on equality for each provided header.

import httpx
from pytest_httpx import HTTPXMock


def test_headers_matching(httpx_mock: HTTPXMock):
    httpx_mock.add_response(match_headers={'User-Agent': 'python-httpx/0.25.0'})

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

Matching on HTTP body

Use match_content parameter to specify the full HTTP body (as bytes) to reply to.

Matching is performed on equality.

import httpx
from pytest_httpx import HTTPXMock


def test_content_matching(httpx_mock: HTTPXMock):
    httpx_mock.add_response(match_content=b"This is the body")

    with httpx.Client() as client:
        response = client.post("https://test_url", content=b"This is the body")
Matching on HTTP JSON body

Use match_json parameter to specify the JSON decoded HTTP body to reply to.

Matching is performed on equality. You can however use unittest.mock.ANY to do partial matching.

import httpx
from pytest_httpx import HTTPXMock
from unittest.mock import ANY

def test_json_matching(httpx_mock: HTTPXMock):
    httpx_mock.add_response(match_json={"a": "json", "b": 2})

    with httpx.Client() as client:
        response = client.post("https://test_url", json={"a": "json", "b": 2})

        
def test_partial_json_matching(httpx_mock: HTTPXMock):
    httpx_mock.add_response(match_json={"a": "json", "b": ANY})

    with httpx.Client() as client:
        response = client.post("https://test_url", json={"a": "json", "b": 2})

Note that match_content or match_files cannot be provided if match_json is also provided.

Matching on HTTP multipart body

Use match_files and match_data parameters to specify the full multipart body to reply to.

Matching is performed on equality.

import httpx
from pytest_httpx import HTTPXMock

def test_multipart_matching(httpx_mock: HTTPXMock):
    httpx_mock.add_response(match_files={"name": ("file_name", b"File content")}, match_data={"field": "value"})

    with httpx.Client() as client:
        response = client.post("https://test_url", files={"name": ("file