Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up

a socket mock framework - for all kinds of socket animals, web-clients included

License

NotificationsYou must be signed in to change notification settings

mindflayer/python-mocket

Repository files navigation

https://github.com/mindflayer/python-mocket/actions/workflows/main.yml/badge.svg?branch=mainhttps://coveralls.io/repos/github/mindflayer/python-mocket/badge.svg?branch=mainhttps://app.codacy.com/project/badge/Grade/6327640518ce42adaf59368217028f14https://img.shields.io/pypi/dm/mocket

A socket mock framework

for all kinds of socketanimals, web-clients included - with gevent/asyncio/SSL support

...and then MicroPython'surequests (mocket >= 3.9.1)

Outside GitHub

Mocket packages are available foropenSUSE,NixOS,ALT Linux,NetBSD, and of course fromPyPI.

Versioning

Starting from3.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.

FYI: the last version compatible with Python 2.7 is3.9.4, bugfixing or backporting of features introduced after that release will only be available as commercial support.

Support it

Star the project on GitHub,Buy Me a Coffee clicking the button below or, even better, contribute with patches or documentation.

Buy Me A Coffee

How to use it

Read the following blog posts if you want to have a big picture of whatMocket is capable of:

The starting point to understand how to useMocket to write a custom mock is the following example:

As next step, you are invited to have a look at the implementation of both the mocks it provides:

Please also have a look at the huge test suite:

Installation

Using pip:

$ pip install mocket

Speedups

Mocket usesxxhash when available instead ofhashlib.md5 for creating hashes, you can install it as follows:

$ pip install mocket[speedups]

Issues

When opening anIssue, please add few lines of code as failing test, or -better- open its relativePull request adding this test to our test suite.

Example of how to mock an HTTP[S] call

Let's create a new virtualenv with all we need:

$ python3 -m venv example$ source example/bin/activate$ pip install pytest requests mocket

As second step, we create an example.py file as the following one:

importjsonfrommocketimportmocketizefrommocket.mockhttpimportEntryimportrequestsimportpytest@pytest.fixturedefresponse():return {"integer":1,"string":"asd","boolean":False,    }@mocketize# use its decoratordeftest_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()assertresponse==mocked_response# OR use its context managerfrommocketimportMocketizerdeftest_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'}    )withMocketizer():mocked_response=requests.get(url_to_mock).json()assertresponse==mocked_response

Let's fire our example test:

$ py.test example.py

How to make Mocket fail when it tries to write to a real socket?

NEW!!! Sometimes you just want your tests to fail when they attempt to use the network.

withMocketizer(strict_mode=True):withpytest.raises(StrictMocketException):requests.get("https://duckduckgo.com/")# OR@mocketize(strict_mode=True)deftest_get():withpytest.raises(StrictMocketException):requests.get("https://duckduckgo.com/")

You can specify exceptions as a list of hosts or host-port pairs.

withMocketizer(strict_mode=True,strict_mode_allowed=["localhost", ("intake.ourmetrics.net",443)]):    ...# OR@mocketize(strict_mode=True,strict_mode_allowed=["localhost", ("intake.ourmetrics.net",443)])deftest_get():    ...

How to be sure that all the Entry instances have been served?

Add this instruction at the end of the test execution:

Mocket.assert_fail_if_entries_not_served()

Example of how to fake socket errors

It's very important that we test non-happy paths.

@mocketizedeftest_raise_exception(self):url="http://github.com/fluidicon.png"Entry.single_register(Entry.GET,url,exception=socket.error())withself.assertRaises(requests.exceptions.ConnectionError):requests.get(url)

Example of how to record real socket traffic

You probably know whatVCRpy is capable of, that's themocket's way of achieving it:

@mocketize(truesocket_recording_dir=tempfile.mkdtemp())deftest_truesendall_with_recording_https():url='https://httpbin.org/ip'requests.get(url,headers={"Accept":"application/json"})resp=requests.get(url,headers={"Accept":"application/json"})assertresp.status_code==200dump_filename=os.path.join(Mocket.get_truesocket_recording_dir(),Mocket.get_namespace()+'.json',    )withio.open(dump_filename)asf:response=json.load(f)assertlen(response['httpbin.org']['443'].keys())==1

HTTPretty compatibility layer

Mocket HTTP mock can work asHTTPretty replacement for many different use cases. Two main features are missing:

  • URL entries containing regular expressions;
  • response body from functions (used mostly to fake errors,mocket doesn't need to do it this way).

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:

importjsonimportaiohttpimportasynciofromunittestimportTestCasefrommocket.plugins.httprettyimporthttpretty,httprettifiedclassAioHttpEntryTestCase(TestCase):@httprettifieddeftest_https_session(self):url='https://httpbin.org/ip'httpretty.register_uri(httpretty.GET,url,body=json.dumps(dict(origin='127.0.0.1')),        )asyncdefmain(l):asyncwithaiohttp.ClientSession(loop=l,timeout=aiohttp.ClientTimeout(total=3)            )assession:asyncwithsession.get(url)asget_response:assertget_response.status==200assertawaitget_response.text()=='{"origin": "127.0.0.1"}'loop=asyncio.new_event_loop()loop.set_debug(True)loop.run_until_complete(main(loop))

What about the other socket animals?

UsingMocket with asyncio based clients:

$ pip install aiohttp

Example:

# `aiohttp` creates SSLContext instances at import-time# that's why Mocket would get stuck when dealing with HTTP# Importing the module while Mocket is in control (inside a# decorated test function or using its context manager would# be enough for making it work), the alternative is using a# custom TCPConnector which always return a FakeSSLContext# from Mocket like this example is showing.importaiohttpimportpytestfrommocketimportasync_mocketizefrommocket.mockhttpimportEntryfrommocket.plugins.aiohttp_connectorimportMocketTCPConnector@pytest.mark.asyncio@async_mocketizeasyncdeftest_aiohttp():"""    The alternative to using the custom `connector` would be importing    `aiohttp` when Mocket is already in control (inside the decorated test).    """url="https://bar.foo/"data= {"message":"Hello"}Entry.single_register(Entry.GET,url,body=json.dumps(data),headers={"content-type":"application/json"},    )asyncwithaiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=3),connector=MocketTCPConnector()    )assession,session.get(url)asresponse:response=awaitresponse.json()assertresponse==data

Works well with others

UsingMocket aspook engine:

$ pip install mocket[pook]

Example:

importpookfrommocket.plugins.pook_mock_engineimportMocketEnginepook.set_mock_engine(MocketEngine)pook.on()url='http://twitter.com/api/1/foobar'status=404response_json= {'error':'foo'}mock=pook.get(url,headers={'content-type':'application/json'},reply=status,response_json=response_json,)mock.persist()requests.get(url)assertmock.calls==1resp=requests.get(url)assertresp.status_code==statusassertresp.json()==response_jsonassertmock.calls==2

First appearance

EuroPython 2013, Florence


[8]ページ先頭

©2009-2025 Movatter.jp