{ "info": { "author": "Michael Williamson", "author_email": "mike@zwobble.org", "bugtrack_url": null, "classifiers": [], "description": "Funk: A mocking framework for Python\n====================================\n\nFunk is a mocking framework for Python, influenced heavily by `JMock `_.\nFunk helps to test modules in isolation by allowing mock objects to be used in place of \"real\" objects.\nFunk is licensed under the 2-clause BSD licence.\n\nInstallation\n------------\n\n.. code-block:: sh\n\n $ pip install funk\n\nExample\n-------\n\nSuppose we have an API for a file storage service.\nWe want to list the names of all files,\nbut the API limits the number of names it will return at a time.\nTherefore, we need to write some code that will keep making requests to the API\nuntil all names have been retrieved.\n\n.. code-block:: python\n\n def fetch_names(file_storage):\n has_more = True\n token = None\n names = []\n \n while has_more:\n response = file_storage.names(token=token)\n names += response.names\n token = response.next_token\n has_more = token is not None\n \n return names \n \n\n import funk\n\n @funk.with_mocks\n def test_request_for_names_until_all_names_are_fetched(mocks):\n file_storage = mocks.mock(FileStorage)\n \n mocks.allows(file_storage).names(token=None).returns(mocks.data(\n next_token=\"\",\n names=[\"a\", \"b\"],\n ))\n mocks.allows(file_storage).names(token=\"\").returns(mocks.data(\n next_token=\"\",\n names=[\"c\", \"d\"],\n ))\n mocks.allows(file_storage).names(token=\"\").returns(mocks.data(\n next_token=None,\n names=[\"e\"],\n ))\n \n assert fetch_names(file_storage) == [\"a\", \"b\", \"c\", \"d\", \"e\"]\n\nBy using a mock object instead of a real instance of ``FileStorage``,\nwe can run our tests without a running instance of the file storage system.\nWe also avoid relying on the implementation of ``FileStorage``,\nmaking our tests more focused and less brittle.\n\nIf you're using pytest,\nthe easiest way to use Funk is as a fixture:\n\n.. code-block:: python\n\n import funk\n import pytest\n \n @pytest.yield_fixture\n def mocks():\n mocks = funk.Mocks()\n yield mocks\n mocks.verify()\n \n def test_request_for_names_until_all_names_are_fetched(mocks):\n file_storage = mocks.mock(FileStorage)\n ...\n\nUsage\n-----\n\nCreating a mock context\n^^^^^^^^^^^^^^^^^^^^^^^\n\nCreate an instance of ``Mocks`` to allow mock objects to be created.\nCall ``Mocks.verify()`` to assert that all expectations have been met.\n\n.. code-block:: python\n\n import funk\n \n def test_case():\n mocks = funk.Mocks()\n ...\n mocks.verify()\n\nUse the decorator ``funk.with_mocks`` to inject a ``mocks`` argument to a function.\n``verify()`` will be automatically invoked at the end of the function.\n\n.. code-block:: python\n\n import funk\n \n @funk.with_mocks\n def test_case(mocks):\n ...\n\nIf using pytest, a fixture is the simplest way to use Funk:\n\n.. code-block:: python\n\n import funk\n import pytest\n \n @pytest.yield_fixture\n def mocks():\n mocks = funk.Mocks()\n yield mocks\n mocks.verify()\n \n def test_case(mocks):\n ...\n\nCreating mock objects\n^^^^^^^^^^^^^^^^^^^^^\n\nCall ``Mocks.mock()`` to create a mock object.\n\n.. code-block:: python\n\n file_storage = mocks.mock()\n\nIf the ``base`` argument is passed,\nonly methods on that type can be mocked:\n\n.. code-block:: python\n\n file_storage = mocks.mock(FileStorage)\n\nThis can be useful to ensure that only existing methods are mocked,\nbut should be avoided if generating methods dynamically, such as by using ``__getattr__``.\n\nSet the ``name`` argument to set the name that should be used in assertion failure messages for the mock:\n\n.. code-block:: python\n\n file_storage = mocks.mock(name=\"file_storage\")\n\nSetting expectations\n^^^^^^^^^^^^^^^^^^^^\n\nTo set up an expectation, use ``funk.allows()`` or ``funk.expects()``.\nFor convenience, these functions are also available on ``Mocks``.\n``funk.allows()`` will let the method be called any number of times, including none.\n``funk.expects()`` will ensure that the method is called exactly once.\nFor instance:\n\n.. code-block:: python\n\n allows(file_storage).names\n\nThis allows the method ``file_storage.names`` to be called with any arguments\nany number of times.\nTo only allow calls with specific arguments, you can invoke ``.names`` as a method:\n\n.. code-block:: python\n\n allows(file_storage).names(token=\"\")\n\nThis will only allow calls with a matching ``token`` keyword argument,\nand no other arguments.\n\nYou can also use matchers from Precisely_ to match arguments:\n\n.. code-block:: python\n\n from precisely import instance_of\n\n allows(file_storage).names(token=instance_of(str))\n\n.. _Precisely: https://pypi.python.org/pypi/precisely\n\nIf more than one expectation is set up on the same method,\nthe first matching expectation is used.\nIf you need to enforce methods being called in a particular order,\nuse sequences.\n\nActions\n~~~~~~~\n\nBy default, a mocked method returns ``None``.\nUse ``returns()`` to return a different value:\n\n.. code-block:: python\n\n allows(file_storage).names().returns([])\n\nUse ``raises()`` to raise an exception:\n\n.. code-block:: python\n\n allows(file_storage).names().raises(Exception(\"Could not connect\"))\n\nSequences\n^^^^^^^^^\n\nA sequence object can be created using ``Mocks.sequence``.\nThe sequencing on objects can then be defined using ``in_sequence(sequence)`` when setting expectations.\nFor instance:\n\n.. code-block:: python\n\n file_storage = mocks.mock(FileStorage)\n file_ordering = mocks.sequence()\n\n expects(file_storage).save(NAME_1, CONTENTS_1).in_sequence(file_ordering)\n expects(file_storage).save(NAME_2, CONTENTS_2).in_sequence(file_ordering)\n", "description_content_type": "", "docs_url": "https://pythonhosted.org/Funk/", "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/mwilliamson/funk", "keywords": "mock", "license": "BSD License", "maintainer": "", "maintainer_email": "", "name": "Funk", "package_url": "https://pypi.org/project/Funk/", "platform": "", "project_url": "https://pypi.org/project/Funk/", "project_urls": { "Homepage": "https://github.com/mwilliamson/funk" }, "release_url": "https://pypi.org/project/Funk/0.5.0/", "requires_dist": null, "requires_python": "", "summary": "A mocking framework for Python", "version": "0.5.0" }, "last_serial": 5552709, "releases": { "0.1": [ { "comment_text": "", "digests": { "md5": "abcaa2e1cc5ac6118cc15a7522e7bea0", "sha256": "2b3dfbef8839a71f17f6263ab5d35888e9b7cf1da080a5c3babd805118eeef1a" }, "downloads": -1, "filename": "Funk-0.1.tar.gz", "has_sig": false, "md5_digest": "abcaa2e1cc5ac6118cc15a7522e7bea0", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14999, "upload_time": "2009-09-28T19:34:38", "url": "https://files.pythonhosted.org/packages/f7/48/d7d72ea73413b1853d46d487a3a28186d2802acf9611eccbed0029c80241/Funk-0.1.tar.gz" } ], "0.2": [ { "comment_text": "", "digests": { "md5": "a3d568e400a99c2bce75ca016e1107c7", "sha256": "caf6a0f2cdcb270c1660e73a4ec686d696818d6a34cc082f995611071f81eb3b" }, "downloads": -1, "filename": "Funk-0.2.tar.gz", "has_sig": false, "md5_digest": "a3d568e400a99c2bce75ca016e1107c7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 17399, "upload_time": "2009-10-19T16:48:03", "url": "https://files.pythonhosted.org/packages/bc/7d/143f75faee0f39978ebfc7ae4f39649372ca91942bbffb0942ca134afae4/Funk-0.2.tar.gz" } ], "0.3": [ { "comment_text": "", "digests": { "md5": "5b46bdf59253b9eb00dcab499385ffe6", "sha256": "16efab6cde81fdde698fa5518222958116e8b71a4fff2f34e0e56a9bf36b6517" }, "downloads": -1, "filename": "Funk-0.3.tar.gz", "has_sig": false, "md5_digest": "5b46bdf59253b9eb00dcab499385ffe6", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 22114, "upload_time": "2010-09-22T00:03:29", "url": "https://files.pythonhosted.org/packages/6e/c6/94de3accff663140abbd28edfe69393359435cbdae0dc95bddfa21ba6a28/Funk-0.3.tar.gz" } ], "0.3.1": [ { "comment_text": "", "digests": { "md5": "f0686785b7a10709025c2600dff92aa0", "sha256": "06a09e0c8ba0ce75e057a9ca487418f1cb3254db62ee0499a3d8e8ac05248fbf" }, "downloads": -1, "filename": "Funk-0.3.1.tar.gz", "has_sig": false, "md5_digest": "f0686785b7a10709025c2600dff92aa0", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 220338, "upload_time": "2013-11-09T01:48:03", "url": "https://files.pythonhosted.org/packages/b6/48/2253e5c5aaf71d95e7038dfc10539b83973cd6c376487ae2b340c2508a99/Funk-0.3.1.tar.gz" } ], "0.4.0": [ { "comment_text": "", "digests": { "md5": "c8e12f5b8e0a313e7d18cd5ff5097d54", "sha256": "390581dc23a8cf16c816cf78c4958bbfee369c32ffe90917fa5f1a8ff886b0a4" }, "downloads": -1, "filename": "Funk-0.4.0.tar.gz", "has_sig": false, "md5_digest": "c8e12f5b8e0a313e7d18cd5ff5097d54", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 220012, "upload_time": "2014-01-14T22:15:51", "url": "https://files.pythonhosted.org/packages/68/05/44e970041b28b8a85f1782b6ecc4dcd82fd4a31a90dc1737e4deea86d915/Funk-0.4.0.tar.gz" } ], "0.5.0": [ { "comment_text": "", "digests": { "md5": "b8c94932c6fc7eaf4f27cd43fa3df6c2", "sha256": "62eeaa238b668171756e75b5bda8a02cea86e8d55c55f4d0417f52246d6f9101" }, "downloads": -1, "filename": "Funk-0.5.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "b8c94932c6fc7eaf4f27cd43fa3df6c2", "packagetype": "bdist_wheel", "python_version": "2.7", "requires_python": null, "size": 10796, "upload_time": "2019-07-18T18:48:24", "url": "https://files.pythonhosted.org/packages/b1/60/e8f3dbe06a3c858a131c6ee3ec11b7a10c313b0c2a64519d889aee8fe647/Funk-0.5.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "869335712359c1a33bc270604aabcf62", "sha256": "59e954b744dacc28785bd81abe11dd9957dc5a4774db949b573f2c3861cfe84c" }, "downloads": -1, "filename": "Funk-0.5.0.tar.gz", "has_sig": false, "md5_digest": "869335712359c1a33bc270604aabcf62", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 22942, "upload_time": "2019-07-18T18:47:45", "url": "https://files.pythonhosted.org/packages/8d/25/fbf23cd90e3fac6068d6dd60110108f174f9a0d9a142aa6d86d8e5a1be74/Funk-0.5.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "b8c94932c6fc7eaf4f27cd43fa3df6c2", "sha256": "62eeaa238b668171756e75b5bda8a02cea86e8d55c55f4d0417f52246d6f9101" }, "downloads": -1, "filename": "Funk-0.5.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "b8c94932c6fc7eaf4f27cd43fa3df6c2", "packagetype": "bdist_wheel", "python_version": "2.7", "requires_python": null, "size": 10796, "upload_time": "2019-07-18T18:48:24", "url": "https://files.pythonhosted.org/packages/b1/60/e8f3dbe06a3c858a131c6ee3ec11b7a10c313b0c2a64519d889aee8fe647/Funk-0.5.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "869335712359c1a33bc270604aabcf62", "sha256": "59e954b744dacc28785bd81abe11dd9957dc5a4774db949b573f2c3861cfe84c" }, "downloads": -1, "filename": "Funk-0.5.0.tar.gz", "has_sig": false, "md5_digest": "869335712359c1a33bc270604aabcf62", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 22942, "upload_time": "2019-07-18T18:47:45", "url": "https://files.pythonhosted.org/packages/8d/25/fbf23cd90e3fac6068d6dd60110108f174f9a0d9a142aa6d86d8e5a1be74/Funk-0.5.0.tar.gz" } ] }