HTTP traffic mocking and expectations made easy
Project description
pook
![Python Versions](https://pypi-camo.freetls.fastly.net/a7b1d9a6670f8a4e1df8dd49a611b54a58911b45/68747470733a2f2f696d672e736869656c64732e696f2f707970692f707976657273696f6e732f706f6f6b2e737667)
Versatile, expressive and hackable utility library for HTTP traffic mocking and expectations made easy in Python. Heavily inspired by gock.
To get started, see the documentation, how it works, FAQ or examples.
Features
Simple, expressive and fluent API.
Provides both Pythonic and chainable DSL API styles.
Full-featured HTTP response definitions and expectations.
Matches any HTTP protocol primitive (URL, method, query params, headers, body…).
Full regular expressions capable mock expectations matching.
Supports most popular HTTP clients via interceptor adapters.
Configurable volatile, persistent or TTL limited mocks.
Works with any testing framework/engine (unittest, pytest, nosetests…).
First-class JSON & XML support matching and responses.
Supports JSON Schema body matching.
Works in both runtime and testing environments.
Can be used as decorator and/or via context managers.
Supports real networking mode with optional traffic filtering.
Map/filter mocks easily for generic or custom mock expectations.
Custom user-defined mock matcher functions.
Simulated raised error exceptions.
Network delay simulation (only available for aiohttp).
Pluggable and hackable API.
Customizable HTTP traffic mock interceptor engine.
Supports third-party mocking engines, such as mocket.
Fits good for painless test doubles.
Does not support WebSocket traffic mocking.
Works with +3.5 (including PyPy).
Dependency-less: just 2 small dependencies for JSONSchema and XML tree comparison.
Supported HTTP clients
pook can work with multiple mock engines, however it provides a built-in one by default, which currently supports traffic mocking in the following HTTP clients:
More HTTP clients can be supported progressively.
Note: only recent HTTP client package versions were tested.
Installation
Using pip package manager (requires pip 1.8+):
pip install --upgrade pook
Or install the latest sources from Github:
pip install -e git+git://github.com/h2non/pook.git#egg=pook
Getting started
See ReadTheDocs documentation:
API
See annotated API reference documention.
Examples
See examples documentation for full featured code and use case examples.
Basic mocking:
import pook
import requests
@pook.on
def test_my_api():
mock = pook.get('http://twitter.com/api/1/foobar', reply=404, response_json={'error': 'not found'})
resp = requests.get('http://twitter.com/api/1/foobar')
assert resp.status_code == 404
assert resp.json() == {"error": "not found"}
assert mock.calls == 1
Using the chainable API DSL:
import pook
import requests
@pook.on
def test_my_api():
mock = (pook.get('http://twitter.com/api/1/foobar')
.reply(404)
.json({'error': 'not found'}))
resp = requests.get('http://twitter.com/api/1/foobar')
assert resp.json() == {"error": "not found"}
assert mock.calls == 1
Using the decorator:
import pook
import requests
@pook.get('http://httpbin.org/status/500', reply=204)
@pook.get('http://httpbin.org/status/400', reply=200)
def fetch(url):
return requests.get(url)
res = fetch('http://httpbin.org/status/400')
print('#1 status:', res.status_code)
res = fetch('http://httpbin.org/status/500')
print('#2 status:', res.status_code)
Simple unittest integration:
import pook
import unittest
import requests
class TestUnitTestEngine(unittest.TestCase):
@pook.on
def test_request(self):
pook.get('server.com/foo').reply(204)
res = requests.get('http://server.com/foo')
self.assertEqual(res.status_code, 204)
def test_request_with_context_manager(self):
with pook.use():
pook.get('server.com/bar', reply=204)
res = requests.get('http://server.com/bar')
self.assertEqual(res.status_code, 204)
Using the context manager for isolated HTTP traffic interception blocks:
import pook
import requests
# Enable HTTP traffic interceptor
with pook.use():
pook.get('http://httpbin.org/status/500', reply=204)
res = requests.get('http://httpbin.org/status/500')
print('#1 status:', res.status_code)
# Interception-free HTTP traffic
res = requests.get('http://httpbin.org/status/200')
print('#2 status:', res.status_code)
Example using mocket Python library as underlying mock engine:
import pook
import requests
from mocket.plugins.pook_mock_engine import MocketEngine
# Use mocket library as underlying mock engine
pook.set_mock_engine(MocketEngine)
# Explicitly enable pook HTTP mocking (optional)
pook.on()
# Target server URL to mock out
url = 'http://twitter.com/api/1/foobar'
# Define your mock
mock = pook.get(url,
reply=404, times=2,
headers={'content-type': 'application/json'},
response_json={'error': 'foo'})
# Run first HTTP request
requests.get(url)
assert mock.calls == 1
# Run second HTTP request
res = requests.get(url)
assert mock.calls == 2
# Assert response data
assert res.status_code == 404
assert res.json() == {'error': 'foo'}
# Explicitly disable pook (optional)
pook.off()
Example using Hy language (Lisp dialect for Python):
(import [pook])
(import [requests])
(defn request [url &optional [status 404]]
(doto (.mock pook url) (.reply status))
(let [res (.get requests url)]
(. res status_code)))
(defn run []
(with [(.use pook)]
(print "Status:" (request "http://server.com/foo" :status 204))))
;; Run test program
(defmain [&args] (run))
Development
Clone the repository:
git clone git@github.com:h2non/pook.git
Install dependencies:
pip install -r requirements.txt -r requirements-dev.txt
Install Python dependencies:
make install
Lint code:
make lint
Run tests:
make test
Generate documentation:
make htmldocs
License
MIT - Tomas Aparicio
v1.1.0 / 2023-01-01
chore(version): bump minor v1.1.0
Switch to Python >= 3.5 and fix latest aiohttp compatability (#83)
fix: remove print call (#81)
v1.0.2 / 2021-09-10
fix(urllib3): interceptor is never really disabled (#68)
Closes #75 Re consider @fluent decorator (#76)
fix(#69): use match keyword in pytest.raises
fix(History): invalid rst syntax
v1.0.1 / 2020-03-24
fix(aiohttp): compatible with non aiohttp projects (#67)
feat(History): add release changes
v1.0.0 / 2020-03-18
fix(aiohttp): use latest version, allow Python 3.5+ for async http client
v0.2.8 / 2019-10-31
fix collections import warning (#61)
v0.2.7 / 2019-10-21
fix collections import warning (#61)
v0.2.6 / 2019-02-01
Add mock.reply(new_response=True) to reset response definition object
v0.2.5 / 2017-10-19
refactor(setup): remove extra install dependency
Fix py27 compatibility (#49)
Add activate_async decorator (#48)
fix typo in pook.mock.Mock.ismatched.__doc__ (#47)
fix README example (#46)
v0.2.4 / 2017-10-03
fix(#45): regex URL issue
fix(travis): allow failures in pypy
feat(docs): add sponsor banner
refactor(History): normalize style
v0.2.3 / 2017-04-28
feat(docs): add supported version for aiohttp
Merge branch ‘master’ of https://github.com/h2non/pook
fix(api): export missing symbol “disable_network”
Update README.rst (#43)
v0.2.2 / 2017-04-03
refactor(compare): disable maxDiff length limit while comparing values
v0.2.1 / 2017-03-25
fix(engine): enable new mock engine on register if needed
fix(engine): remove activate argument before instantiating the Mock
v0.2.0 / 2017-03-18
refactor(engine): do not activate engine on mock declaration if not explicitly requested. This introduces a behavioral library change: you must explicitly use pook.on() to enable pook mock engine.
v0.1.14 / 2017-03-17
feat(docs): list supported HTTP client versions
fix(#41): disable mocks after decorator call invokation
feat(examples): add mock context manager example file
feat(#40): support context manager definitions
feat(#39): improve unmatched request output
feat(docs): add mocket example file
feat(#33): add mocket examples and documentation
v0.1.13 / 2017-01-29
fix(api): mock.calls property should be an int.
v0.1.12 / 2017-01-28
feat(#33): proxy mock definitions into mock.Request
refactor(api): pook.unmatched_requests() now returns a list instead of a lazy tuple.
v0.1.11 / 2017-01-14
refactor(query)
fix(#37): fix URL comparison
fix(#38): proper mock engine interface validation.
v0.1.10 / 2017-01-13
fix(#37): decode byte bodies
feat(setup.py): add author email
v0.1.9 / 2017-01-06
fix(Makefile): remove proper egg file
feat(package): add wheel package distribution support
feat(docs): add documentation links
v0.1.8 / 2016-12-24
fix(assertion): extract regex pattern only when required
feat(examples): add regular expression example
v0.1.7 / 2016-12-18
feat(#33): add support for user defined custom mock engine
v0.1.6 / 2016-12-14
fix(setup.py): force utf-8 encoding
feat(setup.py): add encoding header
feat(api): add debug mode
refactor(docs): minor enhancements
refactor(tests): update URL matcher test cases
refactor(docs): add note about HTTP clients and update features list
fix(setup.py): remove encoding param
fix(tests): use strict equality assertion
0.1.5 / 2016-12-12
fix(matchers): fix matching issue in URL.
refactor(assertion): regex expression based matching must be explicitly enabled.
feat(tests): add initial matchers tests.
0.1.4 / 2016-12-08
refactor(README): minor changes
fix(setup.py): lint error
fix(#32): use explicit encoding while reading files in setup.py
0.1.3 / 2016-12-08
fix(core): several bug fixes.
feat(core): add pending features and major refactors.
feat(matchers): use unittest.TestCase matching engine by default.
0.1.2 / 2016-12-01
fix(matchers): runtime missing variable.
0.1.1 / 2016-12-01
fix: Python 2 dictionary iteration syntax.
feat(docs): add more examples.
fix(matchers): better regular expression comparison support.
0.1.0 / 2016-11-30
First version (still beta)
0.1.0-rc.1 / 2016-11-27
First release candidate version (still beta)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.