⛷️Getting started

🔌Installation

PyPI

$ pip install pytest-remote-response

GitHub

$ git clone https://github.com/devanshshukla99/pytest-remote-response
$ cd pytest-remote-response
$ pip install .

or

$ pip install -e git+git://github.com/devanshshukla99/pytest-remote-response.git#egg=pytest-remote-response

💨Usage

Supported interceptors:

Library

Interceptors

urllib

urllib

_urllib

urllib3

urllib3

_urllib3

requests

requests

aiohttp

aiohttp

🐍🧪pytest plugin

Once, installed the plugin will register automatically with pytest with its configuration options available via pytest --help.

$ pytest --help

The plugin is only applicable to function wrapped with the pytest_response.app.Response.activate() decorator.

Handling connection requests

  • Block remote connections:

$ pytest --remote-block
  • Capture remote requests:

$ pytest --remote-capture
  • Mock remote requests:

$ pytest --remote-response
  • Database dump:

The database dump file can be specified using the remote_response_database ini-config option with pytest. These config options can be set through pytest.ini, pyproject.toml, tox.ini or setup.cfg. Follow the pytest_config docs for more info.

Examples

from pytest_response import response

@response.activate("urllib")
def test_urllib():
    url = "https://www.python.org"
    res = urllib.request.urlopen(url)
    assert res.status == 200
    assert res.read()
$ pytest --remote-block
$ pytest --remote-capture
$ pytest --remote-response

🐱‍👤Standalone package

The tools implemented in this package can be easily ported to any other application, with mimial config required:

Basic usage:

from pytest_response import response

# Setup the database file
response.setup_database("database.json")

# Block outgoing connections
response.configure(remote=False, capture=False, response=False)

# Capture outgoing connections
response.configure(remote=True, capture=True, response=False)

# Mock outgoing connections
response.configure(remote=True, capture=False, response=True)

# Applies the interceptor
response.post({INTERCEPTOR})

...
...

# Cleanup
response.unpost()

Note

Here {INTERCEPTORS} can be str or list

Examples:

Block connections in urllib
# Block outgoing connections for `urllib` library

from pytest_response import response

# Setting up a clean database
response.setup_database("database.json")

# Block outgoing connections
response.configure(remote=False, capture=False, response=False)

# Applies the `urllib` interceptor
response.post("urllib")

# It's important to import the function after setting up `response`,
# to make sure the monkey patched version is used
from urllib.request import urlopen  # noqa

# Since the connections are blocked, this request will
# error out with :class:`~pytest_response.exceptions.RemoteBlockedError`
r = urlopen("https://www.python.org")

# Cleanup
response.unpost()
Capture connections in requests
# Capture outgoing connections for `requests` library

from pytest_response import response

# Setting up a clean database
response.setup_database("database.json")

# Capture outgoing connections
response.configure(remote=True, capture=True, response=False)

# Applies the `requests` interceptor
response.post("requests")

# It's important to import the function after setting up `response`,
# to make sure the monkey patched version is used
import requests  # noqa

# Since the interceptors are in capture mode, the response data and headers
# will be dumped in the database file, i.e. database.json
r = requests.get("https://www.python.org")

# Cleanup
response.unpost()
Mock connections in urllib3
# Mock outgoing connections for `urllib3` library

from pytest_response import response

# Spoof outgoing connections
response.configure(remote=True, capture=False, response=True)

# Applies the `urllib3` interceptor
response.post("urllib3")

# It's important to import the function after setting up `response`,
# to make sure the monkey patched version is used
import urllib3  # noqa

http = urllib3.PoolManager()
url = "https://www.python.org"

# Since the interceptors are in response mode, the response data and headers
# will be spoofed with saved data in the database;
# if the query comes back empty, this request will
# error out with :class:`pytest_response.exceptions.ResponseNotFound`
res = http.request("GET", url)
assert res.status == 200

# Cleanup
response.unpost()
Mock connections in urllib3 using decorator
import urllib3  # noqa

from pytest_response import response

response.configure(remote=True, capture=True, response=False)


@response.activate("urllib3")
def get_url():
    http = urllib3.PoolManager()
    url = "https://www.python.org"

    # Since the interceptors are in response mode, the response data and headers
    # will be spoofed with saved data in the database;
    # if the query comes back empty, this request will
    # error out with :class:`pytest_response.exceptions.ResponseNotFound`
    res = http.request("GET", url)
    assert res.status == 200
    assert res.data


get_url()
Using ResponseDB
# Import the database interface :class:`pytest_response.database.ResponseDB`
from base64 import b64encode

from pytest_response.database import ResponseDB

# Setup the database
db = ResponseDB(path="database.json")

# Insert new element
url = "https://www.python.org"
status = 200
headers = {}
data = b""
db.insert(url=url, status=status, response=data, headers=headers)

# Verify the index
assert b64encode(url.encode()).decode() in db.index()

# Query for an URL
url = "https://www.python.org"
get_status, get_data, get_headers = db.get(url)

# Verify the data is unchanged
assert status == get_status
assert data == get_data
assert headers == get_headers