for all kinds of socket animals, web-clients included - with gevent/asyncio/SSL support
Starting from 3.7.0, Mocket major version will follow the same numbering pattern as Python's and therefore indicate the most recent Python version that is supported.
Star the project on GitHub, Buy Me a Coffee or, even better, contribute with patches or documentation.
Read these three blog posts if you want to have a big picture of what Mocket is capable of:
- https://medium.com/p/mocket-is-alive-and-is-fighting-with-us-b2810d52597a
- https://hackernoon.com/make-development-great-again-faab769d264e
- https://hackernoon.com/httpretty-now-supports-asyncio-e310814704c6
The starting point to understand how to use Mocket to write a custom mock is the following example:
As next step, you are invited to have a look at both the implementation of the two mocks it provides:
- HTTP mock (similar to HTTPretty) - https://github.com/mindflayer/python-mocket/blob/master/mocket/mockhttp.py
- Redis mock (basic implementation) - https://github.com/mindflayer/python-mocket/blob/master/mocket/mockredis.py
Please also have a look at the huge test suite:
- Tests module at https://github.com/mindflayer/python-mocket/tree/master/tests
Using pip:
$ pip install mocket
Mocket uses xxhash when available instead of hashlib.md5 for creating hashes, you can install it as follows:
$ pip install mocket[speedups]
When opening an Issue, please add few lines of code as failing test, or -better- open its relative Pull request adding this test to our test suite.
Let's create a new virtualenv with all we need:
$ virtualenv example $ source example/bin/activate $ pip install pytest requests mocket
As second step, we create an example.py file as the following one:
import json
from mocket import mocketize
from mocket.mockhttp import Entry
import requests
import pytest
@pytest.fixture
def response():
return {
"integer": 1,
"string": "asd",
"boolean": False,
}
@mocketize # use its decorator
def test_json(response):
url_to_mock = 'https://testme.org/json'
Entry.single_register(
Entry.GET,
url_to_mock,
body=json.dumps(response),
headers={'content-type': 'application/json'}
)
mocked_response = requests.get(url_to_mock).json()
assert response == mocked_response
# OR use its context manager
from mocket import Mocketizer
def test_json_with_context_manager(response):
url_to_mock = 'https://testme.org/json'
Entry.single_register(
Entry.GET,
url_to_mock,
body=json.dumps(response),
headers={'content-type': 'application/json'}
)
with Mocketizer():
mocked_response = requests.get(url_to_mock).json()
assert response == mocked_response
Let's fire our example test:
$ py.test example.py
Mocket HTTP mock can work as HTTPretty replacement for many different use cases. Two main features are missing:
- URL entries containing regular expressions;
- response body from functions.
Two features which are against the Zen of Python, at least imho (mindflayer), but of course I am open to call it into question.
Example:
import json
import aiohttp
import asyncio
import async_timeout
from unittest import TestCase
from mocket.plugins.httpretty import HTTPretty, httprettified
class AioHttpEntryTestCase(TestCase):
@httprettified
def test_https_session(self):
url = 'https://httpbin.org/ip'
HTTPretty.register_uri(
HTTPretty.GET,
url,
body=json.dumps(dict(origin='127.0.0.1')),
)
async def main(l):
async with aiohttp.ClientSession(loop=l) as session:
with async_timeout.timeout(3):
async with session.get(url) as get_response:
assert get_response.status == 200
assert await get_response.text() == '{"origin": "127.0.0.1"}'
loop = asyncio.get_event_loop()
loop.set_debug(True)
loop.run_until_complete(main(loop))
Using Mocket with asyncio based clients:
$ pip install aiohttp
Example:
class AioHttpEntryTestCase(TestCase):
@mocketize
def test_http_session(self):
url = 'http://httpbin.org/ip'
body = "asd" * 100
Entry.single_register(Entry.GET, url, body=body, status=404)
Entry.single_register(Entry.POST, url, body=body*2, status=201)
async def main(l):
async with aiohttp.ClientSession(loop=l) as session:
with async_timeout.timeout(3):
async with session.get(url) as get_response:
assert get_response.status == 404
assert await get_response.text() == body
with async_timeout.timeout(3):
async with session.post(url, data=body * 6) as post_response:
assert post_response.status == 201
assert await post_response.text() == body * 2
loop = asyncio.get_event_loop()
loop.run_until_complete(main(loop))
Using Mocket as pook engine:
$ pip install mocket[pook]
Example:
import pook
from mocket.plugins.pook_mock_engine import MocketEngine
pook.set_mock_engine(MocketEngine)
pook.on()
url = 'http://twitter.com/api/1/foobar'
status = 404
response_json = {'error': 'foo'}
mock = pook.get(
url,
headers={'content-type': 'application/json'},
reply=status,
response_json=response_json,
)
mock.persist()
requests.get(url)
assert mock.calls == 1
resp = requests.get(url)
assert resp.status_code == status
assert resp.json() == response_json
assert mock.calls == 2
EuroPython 2013, Florence