Skip to main content

Mock out requests made by ClientSession from aiohttp package

Project description

https://img.shields.io/pypi/v/aioresponses.svg CI

Aioresponses is a helper to mock/fake web requests in python aiohttp package.

For requests module there are a lot of packages that help us with testing (eg. httpretty, responses, requests-mock).

When it comes to testing asynchronous HTTP requests it is a bit harder (at least at the beginning). The purpose of this package is to provide an easy way to test asynchronous HTTP requests.

Installing

$ pip install aioresponses

Supported versions

  • Python 3.10+

  • aiohttp>=3.8,<4.0

Usage

To mock out HTTP request use aioresponses as a method decorator or as a context manager.

Response status code, body, payload (for json response) and headers can be mocked.

Supported HTTP methods: GET, POST, PUT, PATCH, DELETE and OPTIONS.

import aiohttp
import asyncio
from aioresponses import aioresponses

@aioresponses()
def test_request(mocked):
    loop = asyncio.get_event_loop()
    mocked.get('http://example.com', status=200, body='test')
    session = aiohttp.ClientSession()
    resp = loop.run_until_complete(session.get('http://example.com'))

    assert resp.status == 200
    mocked.assert_called_once_with('http://example.com')

for convenience use payload argument to mock out json response. Example below.

as a context manager

import asyncio
import aiohttp
from aioresponses import aioresponses

def test_ctx():
    loop = asyncio.get_event_loop()
    session = aiohttp.ClientSession()
    with aioresponses() as m:
        m.get('http://test.example.com', payload=dict(foo='bar'))

        resp = loop.run_until_complete(session.get('http://test.example.com'))
        data = loop.run_until_complete(resp.json())

        assert dict(foo='bar') == data
        m.assert_called_once_with('http://test.example.com')

aioresponses allows to mock out any HTTP headers

import asyncio
import aiohttp
from aioresponses import aioresponses

@aioresponses()
def test_http_headers(m):
    loop = asyncio.get_event_loop()
    session = aiohttp.ClientSession()
    m.post(
        'http://example.com',
        payload=dict(),
        headers=dict(connection='keep-alive'),
    )

    resp = loop.run_until_complete(session.post('http://example.com'))

    # note that we pass 'connection' but get 'Connection' (capitalized)
    # under the neath `multidict` is used to work with HTTP headers
    assert resp.headers['Connection'] == 'keep-alive'
    m.assert_called_once_with('http://example.com', method='POST')

allows to register different responses for the same url

import asyncio
import aiohttp
from aioresponses import aioresponses

@aioresponses()
def test_multiple_responses(m):
    loop = asyncio.get_event_loop()
    session = aiohttp.ClientSession()
    m.get('http://example.com', status=500)
    m.get('http://example.com', status=200)

    resp1 = loop.run_until_complete(session.get('http://example.com'))
    resp2 = loop.run_until_complete(session.get('http://example.com'))

    assert resp1.status == 500
    assert resp2.status == 200

Repeat response for the same url

E.g. for cases where you want to test retrying mechanisms.

  • By default, repeat=False means the response is not repeated (repeat=1 does the same).

  • Use repeat=n to repeat a response n times.

  • Use repeat=True to repeat a response indefinitely.

import asyncio
import aiohttp
from aioresponses import aioresponses

@aioresponses()
def test_multiple_responses(m):
    loop = asyncio.get_event_loop()
    session = aiohttp.ClientSession()
    m.get('http://example.com', status=500, repeat=2)
    m.get('http://example.com', status=200)  # will take effect after two preceding calls

    resp1 = loop.run_until_complete(session.get('http://example.com'))
    resp2 = loop.run_until_complete(session.get('http://example.com'))
    resp3 = loop.run_until_complete(session.get('http://example.com'))

    assert resp1.status == 500
    assert resp2.status == 500
    assert resp3.status == 200

match URLs with regular expressions

import asyncio
import aiohttp
import re
from aioresponses import aioresponses

@aioresponses()
def test_regexp_example(m):
    loop = asyncio.get_event_loop()
    session = aiohttp.ClientSession()
    pattern = re.compile(r'^http://example\.com/api\?foo=.*$')
    m.get(pattern, status=200)

    resp = loop.run_until_complete(session.get('http://example.com/api?foo=bar'))

    assert resp.status == 200

allows to make redirects responses

import asyncio
import aiohttp
from aioresponses import aioresponses

@aioresponses()
def test_redirect_example(m):
    loop = asyncio.get_event_loop()
    session = aiohttp.ClientSession()

    # absolute urls are supported
    m.get(
        'http://example.com/',
        headers={'Location': 'http://another.com/'},
        status=307
    )

    resp = loop.run_until_complete(
        session.get('http://example.com/', allow_redirects=True)
    )
    assert resp.url == 'http://another.com/'

    # and also relative
    m.get(
        'http://example.com/',
        headers={'Location': '/test'},
        status=307
    )
    resp = loop.run_until_complete(
        session.get('http://example.com/', allow_redirects=True)
    )
    assert resp.url == 'http://example.com/test'

allows to passthrough to a specified list of servers

import asyncio
import aiohttp
from aioresponses import aioresponses

@aioresponses(passthrough=['http://backend'])
def test_passthrough(m, test_client):
    session = aiohttp.ClientSession()
    # this will actually perform a request
    resp = loop.run_until_complete(session.get('http://backend/api'))

also you can passthrough all requests except specified by mocking object

import asyncio
import aiohttp
from aioresponses import aioresponses

@aioresponses(passthrough_unmatched=True)
def test_passthrough_unmatched(m, test_client):
    url = 'https://httpbin.org/get'
    m.get(url, status=200)
    session = aiohttp.ClientSession()
    # this will actually perform a request
    resp = loop.run_until_complete(session.get('http://backend/api'))
    # this will not perform a request and resp2.status will return 200
    resp2 = loop.run_until_complete(session.get(url))

aioresponses allows to throw an exception

import asyncio
from aiohttp import ClientSession
from aiohttp.http_exceptions import HttpProcessingError
from aioresponses import aioresponses

@aioresponses()
def test_how_to_throw_an_exception(m, test_client):
    loop = asyncio.get_event_loop()
    session = ClientSession()
    m.get('http://example.com/api', exception=HttpProcessingError('test'))

    # calling
    # loop.run_until_complete(session.get('http://example.com/api'))
    # will throw an exception.

aioresponses allows to use callbacks to provide dynamic responses

import asyncio
import aiohttp
from aioresponses import CallbackResult, aioresponses

def callback(url, **kwargs):
    return CallbackResult(status=418)

@aioresponses()
def test_callback(m, test_client):
    loop = asyncio.get_event_loop()
    session = ClientSession()
    m.get('http://example.com', callback=callback)

    resp = loop.run_until_complete(session.get('http://example.com'))

    assert resp.status == 418

aioresponses can be used in a pytest fixture

import pytest
from aioresponses import aioresponses

@pytest.fixture
def mock_aioresponse():
    with aioresponses() as m:
        yield m

Features

  • Easy to mock out HTTP requests made by aiohttp.ClientSession

License

  • Free software: MIT license

Credits

This package was created with Cookiecutter and the audreyr/cookiecutter-pypackage project template.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

aioresponses-0.7.9.tar.gz (34.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

aioresponses-0.7.9-py2.py3-none-any.whl (12.8 kB view details)

Uploaded Python 2Python 3

File details

Details for the file aioresponses-0.7.9.tar.gz.

File metadata

  • Download URL: aioresponses-0.7.9.tar.gz
  • Upload date:
  • Size: 34.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.3

File hashes

Hashes for aioresponses-0.7.9.tar.gz
Algorithm Hash digest
SHA256 1dcfa28938fc006f046a98383a7c07ac180be7a492c1ed557f5cd7b0805357d3
MD5 009604490c7f8601840bf05c1cdb4dc2
BLAKE2b-256 28fbe3f08af812b3e66fca511ea1babb9dfddeca5965dea2a4d13b6926e0b1c2

See more details on using hashes here.

File details

Details for the file aioresponses-0.7.9-py2.py3-none-any.whl.

File metadata

  • Download URL: aioresponses-0.7.9-py2.py3-none-any.whl
  • Upload date:
  • Size: 12.8 kB
  • Tags: Python 2, Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.3

File hashes

Hashes for aioresponses-0.7.9-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 94f9617f841c5bd7ee088ed783284f2cf4e6acc85d3933d92fc2fc7bd572a1b0
MD5 e5f3c6dd240b8b47e37b71ca6ad0899e
BLAKE2b-256 71554c77cda7e69c1ac81a32e6895a361e0da9350eb7835a2ddb161a37ef1ce9

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page