Asyncio http mocking. Similar to the responses library used for 'requests'

Related tags

Testingaresponses
Overview

aresponses

image image build status Code style: black

an asyncio testing server for mocking external services

Features

  • Fast mocks using actual network connections
  • allows mocking some types of network issues
  • use regular expression matching for domain, path, method, or body
  • works with https requests as well (by switching them to http requests)
  • works with callables

Usage

Add routes and responses via the aresponses.add method:

def add(
    host_pattern=ANY, 
    path_pattern=ANY, 
    method_pattern=ANY, 
    response="", 
    *, 
    route=None, 
    body_pattern=ANY, m
    match_querystring=False, 
    repeat=1
    )

When a request is received the first matching response will be returned and removed from the routing table. The response argument can be either a string, Response, dict, or list. Use aresponses.Response when you need to do something more complex.

Note that version >=2.0 requires explicit assertions!

@pytest.mark.asyncio
async def test_simple(aresponses):
    aresponses.add("google.com", "/api/v1/", "GET", response="OK")
    aresponses.add('foo.com', '/', 'get', aresponses.Response(text='error', status=500))

    async with aiohttp.ClientSession() as session:
        async with session.get("http://google.com/api/v1/") as response:
            text = await response.text()
            assert text == "OK"
        
        async with session.get("https://foo.com") as response:
            text = await response.text()
            assert text == "error"

    aresponses.assert_plan_strictly_followed()

Assertions

In aresponses 1.x requests that didn't match a route stopped the event loop and thus forced an exception. In aresponses >2.x it's required to make assertions at the end of the test.

There are three assertions functions provided:

  • aresponses.assert_no_unused_routes Raises UnusedRouteError if all the routes defined were not used up.
  • aresponses.assert_called_in_order - Raises UnorderedRouteCallError if the routes weren't called in the order they were defined.
  • aresponses.assert_all_requests_matched - Raises NoRouteFoundError if any requests were made that didn't match to a route. It's likely but not guaranteed that your code will throw an exception in this situation before the assertion is reached.

Instead of calling these individually, it's recommended to call aresponses.assert_plan_strictly_followed() at the end of each test as it runs all three of the above assertions.

Regex and Repeat

host_pattern, path_pattern, method_pattern and body_pattern may be either strings (exact match) or regular expressions.

The repeat argument permits a route to be used multiple times.

If you want to just blanket mock a service, without concern for how many times its called you could set repeat to a large number and not call aresponses.assert_plan_strictly_followed or arespones.assert_no_unused_routes.

@pytest.mark.asyncio
async def test_regex_repetition(aresponses):
    aresponses.add(re.compile(r".*\.?google\.com"), response="OK", repeat=2)

    async with aiohttp.ClientSession() as session:
        async with session.get("http://google.com") as response:
            text = await response.text()
            assert text == "OK"

        async with session.get("http://api.google.com") as response:
            text = await response.text()
            assert text == "OK"

    aresponses.assert_plan_strictly_followed()

Json Responses

As a convenience, if a dict or list is passed to response then it will create a json response. A aiohttp.web_response.json_response object can be used for more complex situations.

@pytest.mark.asyncio
async def test_json(aresponses):
    aresponses.add("google.com", "/api/v1/", "GET", response={"status": "OK"})

    async with aiohttp.ClientSession() as session:
        async with session.get("http://google.com/api/v1/") as response:
            assert {"status": "OK"} == await response.json()

    aresponses.assert_plan_strictly_followed()

Custom Handler

Custom functions can be used for whatever other complex logic is desired. In example below the handler is set to repeat infinitely and always return 500.

import math

@pytest.mark.asyncio
async def test_handler(aresponses):
    def break_everything(request):
        return aresponses.Response(status=500, text=str(request.url))

    aresponses.add(response=break_everything, repeat=math.inf)

    async with aiohttp.ClientSession() as session:
        async with session.get("http://google.com/api/v1/") as response:
            assert response.status == 500

Passthrough

Pass aresponses.passthrough into the response argument to allow a request to bypass mocking.

    aresponses.add('httpstat.us', '/200', 'get', aresponses.passthrough)

Inspecting history

History of calls can be inspected via aresponses.history which returns the namedTuple RoutingLog(request, route, response)

@pytest.mark.asyncio
async def test_history(aresponses):
    aresponses.add(response=aresponses.Response(text="hi"), repeat=2)

    async with aiohttp.ClientSession() as session:
        async with session.get("http://foo.com/b") as response:
            await response.text()
        async with session.get("http://bar.com/a") as response:
            await response.text()

    assert len(aresponses.history) == 2
    assert aresponses.history[0].request.host == "foo.com"
    assert aresponses.history[1].request.host == "bar.com"
    assert "Route(" in repr(aresponses.history[0].route)
    aresponses.assert_plan_strictly_followed()

Context manager usage

import aiohttp
import pytest
import aresponses


@pytest.mark.asyncio
async def test_foo(event_loop):
    async with aresponses.ResponsesMockServer(loop=event_loop) as arsps:
        arsps.add('foo.com', '/', 'get', 'hi there!!')
        arsps.add(arsps.ANY, '/', 'get', arsps.Response(text='hey!'))
        
        async with aiohttp.ClientSession(loop=event_loop) as session:
            async with session.get('http://foo.com') as response:
                text = await response.text()
                assert text == 'hi'
            
            async with session.get('https://google.com') as response:
                text = await response.text()
                assert text == 'hey!'
        

working with pytest-aiohttp

If you need to use aresponses together with pytest-aiohttp, you should re-initialize main aresponses fixture with loop fixture

from aresponses import ResponsesMockServer

@pytest.fixture
async def aresponses(loop):
    async with ResponsesMockServer(loop=loop) as server:
        yield server

If you're trying to use the aiohttp_client test fixture then you'll need to mock out the aiohttp loop fixture instead:

@pytest.fixture
def loop(event_loop):
    """replace aiohttp loop fixture with pytest-asyncio fixture"""
    return event_loop

Contributing

Dev environment setup

  • install pyenv and pyenv-virtualenv - Makes it easy to install specific versions of python and switch between them. Make sure you install the virtualenv bash hook
  • git clone the repo and cd into it.
  • make init - installs proper version of python, creates the virtual environment, activates it and installs all the requirements

Submitting a feature request

  • git checkout -b my-feature-branch
  • make some cool changes
  • make autoformat
  • make test
  • make lint
  • create pull request

Updating package on pypi

  • make deploy

Changelog

2.1.4

  • fix: don't assume utf8 request contents

2.1.3

  • accidental no-op release

2.1.2

  • documentation: add pypi documentation

2.1.1

  • bugfix: RecursionError when aresponses is used in more than 1000 tests (#63)

2.1.0

  • feature: add convenience method add_local_passthrough
  • bugfix: fix https subrequest mocks. support aiohttp_client compatibility

2.0.2

  • bugfix: ensure request body is available in history

2.0.0

Warning! Breaking Changes!

  • breaking change: require explicit assertions for test failures
  • feature: autocomplete works in intellij/pycharm
  • feature: can match on body of request
  • feature: store calls made
  • feature: repeated responses
  • bugfix: no longer stops event loop
  • feature: if dict or list is passed into response, a json response will be generated

1.1.2

  • make passthrough feature work with binary data

1.1.1

  • regex fix for Python 3.7.0

1.1.0

  • Added passthrough option to permit live network calls
  • Added example of using a callable as a response

1.0.0

  • Added an optional match_querystring argument that lets you match on querystring as well

Contributors

The definitive testing tool for Python. Born under the banner of Behavior Driven Development (BDD).

mamba: the definitive test runner for Python mamba is the definitive test runner for Python. Born under the banner of behavior-driven development. Ins

Néstor Salceda 502 Dec 30, 2022
A command-line tool and Python library and Pytest plugin for automated testing of RESTful APIs, with a simple, concise and flexible YAML-based syntax

1.0 Release See here for details about breaking changes with the upcoming 1.0 release: https://github.com/taverntesting/tavern/issues/495 Easier API t

909 Dec 15, 2022
Just a small test with lists in cython

Test for lists in cython Algorithm create a list of 10^4 lists each with 10^4 floats values (namely: 0.1) - 2 nested for iterate each list and compute

Federico Simonetta 32 Jul 23, 2022
WEB PENETRATION TESTING TOOL 💥

N-WEB ADVANCE WEB PENETRATION TESTING TOOL Features 🎭 Admin Panel Finder Admin Scanner Dork Generator Advance Dork Finder Extract Links No Redirect H

56 Dec 23, 2022
Main purpose of this project is to provide the service to automate the API testing process

PPTester project Main purpose of this project is to provide the service to automate the API testing process. In order to deploy this service use you s

4 Dec 16, 2021
Testing - Instrumenting Sanic framework with Opentelemetry

sanic-otel-splunk Testing - Instrumenting Sanic framework with Opentelemetry Test with python 3.8.10, sanic 20.12.2 Step to instrument pip install -r

Donler 1 Nov 26, 2021
a wrapper around pytest for executing tests to look for test flakiness and runtime regression

bubblewrap a wrapper around pytest for assessing flakiness and runtime regressions a cs implementations practice project How to Run: First, install de

Anna Nagy 1 Aug 05, 2021
Fills out the container extension form automatically. (Specific to IIT Ropar)

automated_container_extension Fills out the container extension form automatically. (Specific to IIT Ropar) Download the chrome driver from the websit

Abhishek Singh Sambyal 1 Dec 24, 2021
A web scraping using Selenium Webdriver

Savee - Images Downloader Project using Selenium Webdriver to download images from someone's profile on https:www.savee.it website. Usage The project

Caio Eduardo Lobo 1 Dec 17, 2021
Wraps any WSGI application and makes it easy to send test requests to that application, without starting up an HTTP server.

WebTest This wraps any WSGI application and makes it easy to send test requests to that application, without starting up an HTTP server. This provides

Pylons Project 325 Dec 30, 2022
A twitter bot that simply replies with a beautiful screenshot of the tweet, powered by poet.so

Poet this! Replies with a beautiful screenshot of the tweet, powered by poet.so Installation git clone https://github.com/dhravya/poet-this.git cd po

Dhravya Shah 30 Dec 04, 2022
This package is a python library with tools for the Molecular Simulation - Software Gromos.

This package is a python library with tools for the Molecular Simulation - Software Gromos. It allows you to easily set up, manage and analyze simulations in python.

14 Sep 28, 2022
Yet another python home automation project. Because a smart light is more than just on or off

Automate home Yet another home automation project because a smart light is more than just on or off. Overview When talking about home automation there

Maja Massarini 62 Oct 10, 2022
Selenium-python but lighter: Helium is the best Python library for web automation.

Selenium-python but lighter: Helium Selenium-python is great for web automation. Helium makes it easier to use. For example: Under the hood, Helium fo

Michael Herrmann 3.2k Dec 31, 2022
Getting the most out of your hobby servo

ServoProject by Adam Bäckström Getting the most out of your hobby servo Theory The control system of a regular hobby servo looks something like this:

209 Dec 20, 2022
Subprocesses for Humans 2.0.

Delegator.py — Subprocesses for Humans 2.0 Delegator.py is a simple library for dealing with subprocesses, inspired by both envoy and pexpect (in fact

Amit Tripathi 1.6k Jan 04, 2023
PyAutoEasy is a extension / wrapper around the famous PyAutoGUI, a cross-platform GUI automation tool to replace your boooring repetitive tasks.

PyAutoEasy PyAutoEasy is a extension / wrapper around the famous PyAutoGUI, a cross-platform GUI automation tool to replace your boooring repetitive t

Dingu Sagar 7 Oct 27, 2022
Redis fixtures and fixture factories for Pytest.

Redis fixtures and fixture factories for Pytest.This is a pytest plugin, that enables you to test your code that relies on a running Redis database. It allows you to specify additional fixtures for R

Clearcode 86 Dec 23, 2022
A collection of testing examples using pytest and many other libreris

Effective testing with Python This project was created for PyConEs 2021 Check out the test samples at tests Check out the slides at slides (markdown o

Héctor Canto 10 Oct 23, 2022
A set of pytest fixtures to test Flask applications

pytest-flask An extension of pytest test runner which provides a set of useful tools to simplify testing and development of the Flask extensions and a

pytest-dev 433 Dec 23, 2022