{
"info": {
"author": "Depop",
"author_email": "dev@depop.com",
"bugtrack_url": null,
"classifiers": [
"Environment :: Plugins",
"Framework :: Pytest",
"Intended Audience :: Developers",
"License :: OSI Approved :: Apache Software License",
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3.6"
],
"description": "automock\n========\n\n|PyPI Version| |Build Status|\n\n.. |PyPI Version| image:: http://img.shields.io/pypi/v/automock.svg?style=flat\n :target: https://pypi.python.org/pypi/automock/\n :alt: Latest PyPI version\n\n.. |Build Status| image:: https://circleci.com/gh/depop/python-automock.svg?style=shield&circle-token=cbe5583fec309912d76bfc8b0321f6cfa23b7f6d\n :alt: Build Status\n\nThere are some things that need to be mocked in unit tests.\n\nFor example: API clients for other backend services - we don't want to run an\ninstance of the other service just for our unit tests. The other service will\nhave its own tests and we only want to test that our code confiorms to the API\ncontract of the other service. Similarly for 3rd party services - we don't want\nour unit tests to connect out over the internet to talk to the 3rd party service\n(even if they offer a 'sandbox' test environment) for the same reasons as above,\nand because this is a recipe for flaky tests.\n\n(There is certainly a role for integration tests which do make live calls to\nother services, but the bulk of tests won't be this kind and need mocking).\n\nPython has the excellent `mock `_ library to help with this.\n\nHowever, say you have six API clients for backend services which are used\nextensively in many places in code for your mobile app backend. You're going to\nend up with a big 'stack' of patch decorators on many tests, e.g.:\n\n.. code:: python\n\n @mock.patch('services.users.client.get_user', return_value=MockUser(id=1))\n @mock.patch('services.products.client.get_product', return_value=MockProduct(id=1))\n @mock.patch('services.paypal.client.make_payment', return_value=PaypalResult('success'))\n def test_some_web_view(self, *mocks)\n\nSay you have thousands of unit tests, these decorators need applying to many of\nthem. Every time you write a new test you'll need to remember to patch things.\n\nEnter ``automock``.\n\nBasically we want some functions to be 'mocked by default' when running tests.\nBut we also need to be able to easily replace the default mocks in some cases,\nwhere the test needs a specific return value. ``automock`` makes this easy-ish.\n\n\nUsage\n-----\n\n.. code:: bash\n\n pip install automock\n\n\nIntroduction\n~~~~~~~~~~~~\n\nThe key idea is that we define a 'mock factory' for each function we want to be\nautomocked. When called without arguments the factory should return a suitable\n'default' mock that will allow most tests to pass. The default mock factory is\njust ``MagicMock`` from the ``mock`` library.\n\nRegistering a function to be mocked is simple:\n\n.. code:: python\n\n import automock\n\n automock.register('services.users.client.get_user')\n\nBy default this provides a ``MagicMock`` and is equivalent to decorating *all*\nyour test cases with:\n\n.. code:: python\n\n @mock.patch('services.users.client.get_user')\n\n(for more scenarios see `Customising mock factories`_ below)\n\nFor this to work you just need to do two things.\n\n#. You need to ensure that the modules containing ``automock.register``\n calls get imported before the tests run. To achieve this we have an\n ``AUTOMOCK_REGISTRATION_IMPORTS`` config setting. This should contain string paths\n to modules containing registration calls, e.g.:\n\n .. code:: python\n\n AUTOMOCK_REGISTRATION_IMPORTS = (\n 'services.users.test_mocks',\n 'services.products.test_mocks',\n 'services.paypal.test_mocks',\n )\n\n#. If you're running your tests under `pytest `_\n then you don't need to do anything else - Automock registers a pytest plugin\n (named ``automock`` in pytest) that ensures your test cases all run patched.\n\n#. If you're running under another test-runner then your test cases need to inherit\n from one of our helper classes, e.g.:\n\n .. code:: python\n\n from automock import AutomockTestCase, AutomockTestCaseMixin\n\n\n class TestWebViews(AutomockTestCase):\n ...\n\n\n class TestSpecialViews(AutomockTestCaseMixin, MyCustomTestCase):\n ...\n\n This will ensure the mock patches get applied before the tests run, and stopped\n afterwards.\n\n Alternatively you can start/stop patching manually:\n\n .. code:: python\n\n from unittest import TestCase\n\n import automock\n\n\n class TestStuff(TestCase):\n\n # as a decorator\n @automock.activate()\n def test_stuff(self):\n # automocks active\n ...\n\n # as a context-manager\n def test_other_stuff(self):\n # automocks inactive\n ...\n with automock.activate():\n # automocks active\n ...\n\n # automocks inactive\n\n\nConfiguration\n~~~~~~~~~~~~~\n\nSettings are intended to be configured primarily via a python file, such\nas your existing Django ``settings.py``. To bootstrap this, there are a couple\nof **env vars** to control how config is loaded:\n\n- ``AUTOMOCK_APP_CONFIG``\n should be an import path to a python module, for example:\n ``AUTOMOCK_APP_CONFIG=django.conf.settings``\n- ``AUTOMOCK_CONFIG_NAMESPACE``\n Sets the prefix used for loading further config values from env and\n config file. Defaults to ``AUTOMOCK``.\n\nThe following config keys are available (and are prefixed with\n``AUTOMOCK_`` by default, see ``AUTOMOCK_CONFIG_NAMESPACE`` above):\n\n- ``_REGISTRATION_IMPORTS`` list of import paths to modules\n containing ``automock.register`` calls\n\n\nPatching and imports\n~~~~~~~~~~~~~~~~~~~~\n\nAn **important point to note** about the path you mock:\n\nThis has the same caveats as when using ``mock.patch`` directly. Namely that\nyou must patch the path *where it is imported*.\n\nFor example if you do:\n\n.. code:: python\n\n # mypackage/mymodule.py\n\n from services.product.client import get_product\n\nWhen you patch it:\n\n.. code:: python\n\n # won't work:\n patch('services.product.client.get_product')\n\n # works:\n patch('mypackage.mymodule.get_product')\n\nDON'T DO THIS (see this\n`blog post `_\nfor more details).\n\nThis import style will cause us problems if we want to mock-by-default all\nusages of a particular function, because we only register a single path to mock.\n\nInstead you need to use one of the following import styles *everywhere* in your\ncodebase that the function to mocked is used:\n\n.. code:: python\n\n # mypackage/mymodule.py\n\n # either\n from services.product import client as product_client\n product_client.get_product(*args)\n\n # or\n import services.product.client as product_client\n product_client.get_product(*args)\n\nThis will ensure that we can:\n\n.. code:: python\n\n automock.register('services.product.client.get_product')\n\nand have that work reliably.\n\n**NOTE:**\n\nAlways ``import automock`` and use as ``automock.register`` to ensure there is\nonly one registry active.\n\n\nCustomising mock factories\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nIt's likely you need to do more than provide a bare ``MagicMock``. For example\nwe might want to customise the response based on some values from the request.\n\nIn ``mock.Mock`` this is achieved via a 'side effect'. So we might want to\ndefine our mock factory like this:\n\n.. code:: python\n\n def batch_counters_mock(return_value=None, side_effect=None, *args, **kwargs):\n if return_value is None and side_effect is None:\n def side_effect(product_ids, *args, **kwargs):\n return {str(p_id): 0 for p_id in product_ids}\n return mock.MagicMock(return_value=return_value, side_effect=side_effect, *args, **kwargs)\n\n automock.register('services.products.client.batch_counters', batch_counters_mock)\n\nNote that we passed the custom mock factory as second argument to ``register``.\n\nAs an alternative we can use decorator syntax:\n\n.. code:: python\n\n @automock.register('services.products.client.batch_counters')\n def batch_counters_mock(return_value=None, side_effect=None, *args, **kwargs):\n if return_value is None and side_effect is None:\n def side_effect(product_ids, *args, **kwargs):\n return {str(p_id): 0 for p_id in product_ids}\n return mock.MagicMock(return_value=return_value, side_effect=side_effect, *args, **kwargs)\n\nNow in our tests we can:\n\n.. code:: python\n\n import services.products.client as products_client\n\n def test_counters():\n counters = products_client.batch_counters([1, 2])\n # we got a default value for each of the ids we passed in:\n assert counters == {'1': 0, '2': 0}\n\n(This is a useless test of course, it's just to demonstrate the mocking)\n\nOkay. What if we need a custom return value for a particular test?\n\nWell, firstly the regular ``mock.patch`` still works, you could apply that in\nyour test case.\n\nAutomock also provides a ``swap_mock`` helper that allows us to take advantage\nof our custom mock factory.\n\nLet's say our factory looks like:\n\n.. code:: python\n\n @automock.register('services.things.client.do_something')\n def do_something_mock(success=True):\n if success:\n return mock.MagicMock(return_value='OK')\n else:\n return mock.MagicMock(side_effect=requests.HTTPError())\n\nIn our tests we can:\n\n.. code:: python\n\n import pytest\n import requests\n from automock import swap_mock\n\n import services.things.client as things_client\n\n def test_success():\n # default mock from factory gives success response\n assert things_client.do_something() == 'OK'\n\n @swap_mock('services.things.client.do_something', success=False)\n def test_fail():\n # swap mock applies a customised mock from our factory\n with pytest.raises(requests.HTPPError):\n things_client.do_something()\n\nWhat happened here is that the ``*args, **kwargs`` from our ``swap_mock`` call\nare passed through to the ``do_something_mock`` to *get a new mock* which is\nthen applied in place of the default.\n\nWe can also use this as a context manager:\n\n.. code:: python\n\n import pytest\n import requests\n from automock import swap_mock\n\n import services.things.client as things_client\n\n def test_do_something():\n assert things_client.do_something() == 'OK'\n\n with swap_mock('services.things.client.do_something', success=False):\n with pytest.raises(requests.HTPPError):\n things_client.do_something()\n\n assert things_client.do_something() == 'OK'\n\n\nChecking mocked calls\n~~~~~~~~~~~~~~~~~~~~~\n\nIt's common in tests to want to check if a mocked function was called, and\nwith correct arguments etc. If you use ``mock.patch`` directly this is easy\nbecause it returns the mock object to you.\n\nAutomock provides the ``get_mock`` helper to achieve the same thing:\n\n.. code:: python\n\n from automock import get_mock\n\n import services.things.client as things_client\n\n def test_success():\n assert things_client.do_something() == 'OK'\n mocked = get_mock('services.things.client.do_something')\n assert mocked.called\n\n\nTesting the automocked functions\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nOk, so you've mocked your API clients or whatever. How do you test the mocked\nfunctions themselves if they're mocked out everywhere?\n\nFirstly, you could just not inherit from ``AutomockTestCase`` in those tests.\n\nBut maybe you have a bunch of other automocks you want to keep in place still.\n\nAutomock provides an ``unmock`` helper:\n\n.. code:: python\n\n import pytest\n import responses\n from automock import unmock\n\n import services.things.client as things_client\n\n @responses.activate\n @unmock('services.things.client.do_something')\n def test_do_something_not_found():\n responses.add(responses.GET, 'https://thingservice.ourcompany.com/api/1/something',\n json={'error': 'Not Found'}, status=404)\n with pytest.raises(requests.HTPPError):\n things_client.do_something()\n\n(for functions which make HTTP calls we recommend the excellent\n`responses `_ library)\n\nHere we have un-mocked our client method so that we can test that it correctly\nhandles a 404 response from the remote service.\n\n\nCompatibility\n-------------\n\nThis project is tested against:\n\n=========== ===\nPython 2.7 * \nPython 3.6 * \n=========== ===\n\nRunning the tests\n-----------------\n\nCircleCI\n~~~~~~~~\n\n| The easiest way to test the full version matrix is to install the\n CircleCI command line app:\n| https://circleci.com/docs/2.0/local-jobs/\n| (requires Docker)\n\nThe cli does not support 'workflows' at the moment so you have to run\nthe two Python version jobs separately:\n\n.. code:: bash\n\n circleci build --job python-2.7\n\n.. code:: bash\n\n circleci build --job python-3.6\n\npy.test (single python version)\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nIt's also possible to run the tests locally, allowing for debugging of\nerrors that occur.\n\nNow decide which Python version you want to test and create a virtualenv:\n\n.. code:: bash\n\n pyenv virtualenv 3.6.4 automock\n pip install -r requirements-test.txt\n\nNow we can run the tests:\n\n.. code:: bash\n\n make test",
"description_content_type": "",
"docs_url": null,
"download_url": "",
"downloads": {
"last_day": -1,
"last_month": -1,
"last_week": -1
},
"home_page": "https://github.com/depop/python-automock",
"keywords": "",
"license": "Apache 2.0",
"maintainer": "",
"maintainer_email": "",
"name": "automock",
"package_url": "https://pypi.org/project/automock/",
"platform": "",
"project_url": "https://pypi.org/project/automock/",
"project_urls": {
"Homepage": "https://github.com/depop/python-automock"
},
"release_url": "https://pypi.org/project/automock/1.2.0/",
"requires_dist": null,
"requires_python": "",
"summary": "Utility to allow some functions to be 'mocked by default' when running tests.",
"version": "1.2.0"
},
"last_serial": 4955254,
"releases": {
"1.0.0": [
{
"comment_text": "",
"digests": {
"md5": "90438dc7ff8218c4ad03cbe5f8f5c59f",
"sha256": "bc6456d79bc93ca7405005f9967bcba49da37a917b218f0c2951178ac574b921"
},
"downloads": -1,
"filename": "automock-1.0.0.tar.gz",
"has_sig": false,
"md5_digest": "90438dc7ff8218c4ad03cbe5f8f5c59f",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 9959,
"upload_time": "2018-03-13T15:16:47",
"url": "https://files.pythonhosted.org/packages/a8/b5/f0709eaf9604189f850a4d3e0d2be8070368589e45f7de2777afacc2841e/automock-1.0.0.tar.gz"
}
],
"1.0.1": [
{
"comment_text": "",
"digests": {
"md5": "7c8d8c4f75407ee8fa69c3c7a50de683",
"sha256": "10b3faef03b66e54cac4578330a86a25f22198df1f9f5f5ccac2169e65585ff3"
},
"downloads": -1,
"filename": "automock-1.0.1.tar.gz",
"has_sig": false,
"md5_digest": "7c8d8c4f75407ee8fa69c3c7a50de683",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 10066,
"upload_time": "2018-03-13T16:28:34",
"url": "https://files.pythonhosted.org/packages/5e/4a/c1f847a5cd219691bff4ff9e9353e36d90ef05ab122427d55d8fe3fe95e6/automock-1.0.1.tar.gz"
}
],
"1.0.2": [
{
"comment_text": "",
"digests": {
"md5": "e76eba4a3dfd56e844372a319eb47ddc",
"sha256": "93f49e4d17551a7609d6e7f6bde0f65d70d84a54215b62df857ead260ca4e288"
},
"downloads": -1,
"filename": "automock-1.0.2.tar.gz",
"has_sig": false,
"md5_digest": "e76eba4a3dfd56e844372a319eb47ddc",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 10089,
"upload_time": "2018-03-13T16:37:47",
"url": "https://files.pythonhosted.org/packages/ee/00/a99c3bd8e984f3f97b3dab309a3f1335642390143e2d277fc8a6ba793c90/automock-1.0.2.tar.gz"
}
],
"1.0.3": [
{
"comment_text": "",
"digests": {
"md5": "0c94abd200a949c2b0ac811942467437",
"sha256": "a739868c90b5f8e3f4f51c2d082c1b640fd99232fbd7a1a18c1edb9e75f9c656"
},
"downloads": -1,
"filename": "automock-1.0.3.tar.gz",
"has_sig": false,
"md5_digest": "0c94abd200a949c2b0ac811942467437",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 10321,
"upload_time": "2018-03-13T16:41:08",
"url": "https://files.pythonhosted.org/packages/d8/5d/e10872866d332c0cfd6904229f854743d0f00dff62439fc824f691aaca05/automock-1.0.3.tar.gz"
}
],
"1.0.4": [
{
"comment_text": "",
"digests": {
"md5": "c5515ac04b6a966368575060e1697bc7",
"sha256": "a3a0bf51e1daf5d8bc22a0cdbd5189ba9fd506a52c8bc87c16af6aa37b993dc9"
},
"downloads": -1,
"filename": "automock-1.0.4.tar.gz",
"has_sig": false,
"md5_digest": "c5515ac04b6a966368575060e1697bc7",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 10309,
"upload_time": "2018-03-14T13:20:47",
"url": "https://files.pythonhosted.org/packages/1c/b8/27ecef6e439734e62a629dec1ec1ffb518757f70c9a7ebc1e3ae470f1e6a/automock-1.0.4.tar.gz"
}
],
"1.1.0": [
{
"comment_text": "",
"digests": {
"md5": "84380c90a0fc24ea5d19d3844e08ab34",
"sha256": "b371bfcb429d965156128413551932d37abbe71bdcdf8947e1b519c30668897b"
},
"downloads": -1,
"filename": "automock-1.1.0.tar.gz",
"has_sig": false,
"md5_digest": "84380c90a0fc24ea5d19d3844e08ab34",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 11012,
"upload_time": "2018-03-16T22:10:03",
"url": "https://files.pythonhosted.org/packages/c5/7f/1ede3985bacbfda27c519bb03656b0d277542494eded0377524f14c758e4/automock-1.1.0.tar.gz"
}
],
"1.1.0a1": [
{
"comment_text": "",
"digests": {
"md5": "b38ce396d578747a81796a982cd299fe",
"sha256": "ec6bd15d38e5e59e7c9e88e66027165286249d97fc29a48ba247812a55f7abc9"
},
"downloads": -1,
"filename": "automock-1.1.0a1.tar.gz",
"has_sig": false,
"md5_digest": "b38ce396d578747a81796a982cd299fe",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 11007,
"upload_time": "2018-03-16T22:09:45",
"url": "https://files.pythonhosted.org/packages/9d/b0/f6a66b1c32631a83b4938a6da626b86fdbf2b5647849c8415780160d6f47/automock-1.1.0a1.tar.gz"
}
],
"1.1.1": [
{
"comment_text": "",
"digests": {
"md5": "ade365d2d1c80e3a2311a270d4d4632e",
"sha256": "b615f48b3ff0406f60974015ea9a41bf709615f65d77339a88b7e6d8a7b3dc92"
},
"downloads": -1,
"filename": "automock-1.1.1.tar.gz",
"has_sig": false,
"md5_digest": "ade365d2d1c80e3a2311a270d4d4632e",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 11084,
"upload_time": "2019-02-20T12:19:13",
"url": "https://files.pythonhosted.org/packages/12/b9/6b2ee273106d93891f3b19ec85359fb7ca7bab2cc5f16ffb875f989e860c/automock-1.1.1.tar.gz"
}
],
"1.2.0": [
{
"comment_text": "",
"digests": {
"md5": "cbbf95bc3450c7cf3f221ecf78fab84b",
"sha256": "70c96d7293749ed60adccd28e43165026395cc1750cf90084aeb38e2d1bcba3e"
},
"downloads": -1,
"filename": "automock-1.2.0.tar.gz",
"has_sig": false,
"md5_digest": "cbbf95bc3450c7cf3f221ecf78fab84b",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 11088,
"upload_time": "2019-03-18T18:05:48",
"url": "https://files.pythonhosted.org/packages/3c/ba/b84676809b3528322ca61fcb6703b3704fe4c4b915b76c7d6959fddcbd1f/automock-1.2.0.tar.gz"
}
]
},
"urls": [
{
"comment_text": "",
"digests": {
"md5": "cbbf95bc3450c7cf3f221ecf78fab84b",
"sha256": "70c96d7293749ed60adccd28e43165026395cc1750cf90084aeb38e2d1bcba3e"
},
"downloads": -1,
"filename": "automock-1.2.0.tar.gz",
"has_sig": false,
"md5_digest": "cbbf95bc3450c7cf3f221ecf78fab84b",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 11088,
"upload_time": "2019-03-18T18:05:48",
"url": "https://files.pythonhosted.org/packages/3c/ba/b84676809b3528322ca61fcb6703b3704fe4c4b915b76c7d6959fddcbd1f/automock-1.2.0.tar.gz"
}
]
}