{ "info": { "author": "Luke Park", "author_email": "luke@p4rk.dev", "bugtrack_url": null, "classifiers": [ "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3 :: Only", "Topic :: Software Development :: Testing" ], "description": "# Known Side Effects\n\n[![Codacy Badge](https://api.codacy.com/project/badge/Grade/393832636c36453eb382b56b4f6dcb0f)](https://www.codacy.com/app/P4rk/known_side_effects?utm_source=github.com&utm_medium=referral&utm_content=P4rk/known_side_effects&utm_campaign=Badge_Grade)\n[![Coverage Badge](https://img.shields.io/badge/coverage-97%25-lgreen.svg)](https://shields.io/)\n[![PyPI pyversions](https://img.shields.io/pypi/pyversions/known-side-effects.svg)](https://pypi.python.org/pypi/known-side-effects/)\n[![PyPI version fury.io](https://badge.fury.io/py/known-side-effects.svg)](https://pypi.python.org/pypi/known-side-effects/)\n[![PyPI license](https://img.shields.io/pypi/l/known-side-effects.svg)](https://pypi.python.org/pypi/known-side-effects/)\n\n\n\n\n\nA test utility library to help write explict side effects for mocked objects.\n\nMocks side effects are manipulated by `when` and `then` functions.\n\n```python\nmock.when(...).then(...)\n```\n\nTo enable this extend the mock class in you tests.\n\n```python\nimport known_side_effects\nfrom unittest.mock import Mock\n...\nknown_side_effects.extend(Mock)\n```\n\n## When\n\nAll parameters in the `when` function are used to define the expected parameters for the side effect.\n\n```python\nmock.when('argument_one', arg='argument_two').then(...)\n```\nIf the mock is called with parameters that don't match any of the specified parameter sets then an `UnmatchedArguments` exception is raised. The arguments have to match exactly.\n\nE.g. Given `mock.when('argument_one', arg='argument_two').then(...)` when the mock is called with the parameters in the table below an `UnmatchedArguments` is either raised or not raised. \n\n| Parameters \t\t\t\t\t\t\t\t\t | Raises |\n|--------------------------------------------|--------|\n| `mock('argument_one', arg='argument_two')` | False |\n| `mock(arg='argument_two')` | True |\n| `mock('argument_one')` \t\t\t\t\t | True | \n\n\nMultiple sets of parameters to match can be specified.\n\n```python\nmock.when('first_specified_argument').then(...)\nmock.when('second_specified_argument').then(...)\nmock.when('third_specified_argument').then(...)\n```\n\n#### Chaining\nCalling the when function with exactly the same arguments will allow you to append to the responses.\n\n```python\nmock.when('arg').then('response_one')\nmock.when('arg').then('response_two')\n```\nis the same as\n```python\nmock.when('arg').then('response_one').then('response_two')\n```\n\n## Then\nThe `then` function specifies what the known side effect should do when parameters are matched. By default it will just return what has been passed into the `then` function. \n\n```python\nfrom unittest.mock import Mock\n...\nresponse_one = Mock()\nmock = Mock()\n\nmock.when(...).then(response_one)\n\nassert mock(...) == response_one\n```\n\nTo raise an exception rather that return a value call `then_raise` rather than `then`. An exception will be raised instead of returned.\n\n```python\nfrom unittest.mock import Mock\n...\nexception = Exception()\nmock = Mock()\n\nmock.when(...).then_raise(exception)\n\nmock(...) # Raises the exception\n```\nYou can also chain the `then` functions to return multiple different reponses.\nEach response will be returned once until the last response. Once the last response is reached then that reponse will be the only thing returned.\n\n```python\nfrom unittest.mock import Mock\n...\nexception = Exception()\nresponse_one = Mock()\nmock = Mock()\n\nmock.when(...).then(response_one).then_raise(exception)\n\nassert mock(...) == response_one\nmock(...) # Raises the exception\nmock(...) # Raises the exception\n```\n\n## Otherwise\n\nYou can specify default return values on a mock by calling otherwise. If the mock is called without \nmatching any arguments then the otherwise value will returned.\n```python\nmock.when('arg').then(...).otherwise('otherwise')\n\nassert mock('not arg') == 'otherwise'\n```\nYou can also raise an exception by default\n```python\nmock.when(...).then(...).otherwise_raise(Exception())\n```\n\n\n## Always\n\nYou can specify the mock to always return the same response regardless of what arguments it is called with.\n```python\nmock.when().always('response')\n\nassert mock(...) == 'response'\n```\nYou can also raise an exception\n```python\nmock.when().always_raise(Exception())\n```\n\n\n## Reset\n\nYou can reset the the known side effects on a mock by passing it the `reset` function.\n\n```python\n\nfrom unittest.mock import Mock\nfrom known_side_effects import reset\n...\n\nmock = Mock()\n\nmock.when(...).then(...)\n\nreset(mock)\n\nmock(...) # raises an UnmatchedArguments exception\n```\n\n\n## Gotcha\nWhen calling the `mock` after specifying multiple known side effects, the first matched set of parameters will be executed. The order of matching is the order that the known side effects are defined in. If multiple arguments are specified where one matches a super set of the other (see Matchers) then the first matched will be executed. e.g.\n\n```python\nfrom unittest.mock import Mock\nfrom known_side_effects import AnyArg\n...\nresponse_one = Mock()\nresponse_two = Mock()\nargument_one = Mock()\nargument_two = Mock()\n\nmock.when(argument_one).then(response_one)\nmock.when(AnyArg()).then(response_two)\n...\nassert mock(argument_one) == response_one\nassert mock(argument_two) == response_two\n\n```\nIf the order of the known side effects were reversed, the mock would only ever return `response_two`. This is due to the fact that the `Any` matched will match all parameters, therefore never attempting to match `argument_one` as it has already found a match. e.g.\n\n```python\nfrom unittest.mock import Mock\nfrom known_side_effects import AnyArg\n...\nresponse_one = Mock()\nresponse_two = Mock()\nargument_one = Mock()\nargument_two = Mock()\n\nmock.when(AnyArg()).then(response_two) # These two lines have swapped\nmock.when(argument_one).then(response_one) # These two lines have swapped\n\n...\n# This will raise an AssertionError as calling the mock with argument_one now\n# returns response_two and not response_one\nassert mock(argument_one) == response_one \nassert mock(argument_two) == response_two\n\n```\n\n## Matchers\n\nMatchers can be passed to known side effects as parameters. They are implementations of [hamcrest matchers](https://github.com/hamcrest/PyHamcrest). Matchers will only match a single parameter.\n\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/P4rk/known_side_effects", "keywords": "", "license": "", "maintainer": "", "maintainer_email": "", "name": "known-side-effects", "package_url": "https://pypi.org/project/known-side-effects/", "platform": "", "project_url": "https://pypi.org/project/known-side-effects/", "project_urls": { "Homepage": "https://github.com/P4rk/known_side_effects" }, "release_url": "https://pypi.org/project/known-side-effects/0.1.1/", "requires_dist": [ "PyHamcrest (>=1.9.0)" ], "requires_python": "", "summary": "A test utility library to help write explict side effects for mocked objects", "version": "0.1.1" }, "last_serial": 5624591, "releases": { "0.0.1": [ { "comment_text": "", "digests": { "md5": "17f1d4b8cff5a89f4c230fc00279bc9e", "sha256": "68f7e61d576cd26c20769ce3ece722df125e62619b2d648d065b758b322a8e73" }, "downloads": -1, "filename": "known_side_effects-0.0.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "17f1d4b8cff5a89f4c230fc00279bc9e", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 10646, "upload_time": "2019-07-06T16:38:45", "url": "https://files.pythonhosted.org/packages/21/51/76a0b53d144f78837c184ce2c3e60b93c6e00172979241516453234e6930/known_side_effects-0.0.1-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "46af5839f3b12fdacb7462c26fcd767f", "sha256": "d44b281162167efc38e79ef58e238f24c19d4934d05193c9236337d8ad96882e" }, "downloads": -1, "filename": "known_side_effects-0.0.1-py3-none-any.whl", "has_sig": false, "md5_digest": "46af5839f3b12fdacb7462c26fcd767f", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 10607, "upload_time": "2019-07-06T16:38:47", "url": "https://files.pythonhosted.org/packages/00/ac/857ef76af10394d96c00b545e64c8cd7a11eaa3718bc994e3803b8ea8f97/known_side_effects-0.0.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "fcb6999d37472ec91e1394832c26d9d7", "sha256": "837dd8f606eda22da5ea8c642320b0c5e8a4262495ceb01c5410ca39f06a8143" }, "downloads": -1, "filename": "known_side_effects-0.0.1.tar.gz", "has_sig": false, "md5_digest": "fcb6999d37472ec91e1394832c26d9d7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5329, "upload_time": "2019-07-06T16:38:49", "url": "https://files.pythonhosted.org/packages/1a/2a/c413a255e8e6ddfb000168c674791e61af0f4dff26229722d7da28097536/known_side_effects-0.0.1.tar.gz" } ], "0.0.2": [ { "comment_text": "", "digests": { "md5": "836d44d06c01cb0364be9dbe5d016243", "sha256": "7750f20f8af5de4c94894fee03f4ce6245e49927a5e548c901415bf34e8e438f" }, "downloads": -1, "filename": "known_side_effects-0.0.2-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "836d44d06c01cb0364be9dbe5d016243", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 10646, "upload_time": "2019-07-06T16:48:49", "url": "https://files.pythonhosted.org/packages/ba/25/e5a4f60f887d5620abff7162547e47eb205d5afb4cdb8413cfed4f8f77d2/known_side_effects-0.0.2-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "679529672a5ec7384c52ae5cb9edd680", "sha256": "76fd5e9b276cb3dc4b987c402261ab5194691ec334ab79150b1d3d2c3d3af659" }, "downloads": -1, "filename": "known_side_effects-0.0.2.tar.gz", "has_sig": false, "md5_digest": "679529672a5ec7384c52ae5cb9edd680", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5330, "upload_time": "2019-07-06T16:48:51", "url": "https://files.pythonhosted.org/packages/4d/df/038117461086195c4b67a8a644fb9033d956db77b26f17384341901d8037/known_side_effects-0.0.2.tar.gz" } ], "0.1.0": [ { "comment_text": "", "digests": { "md5": "f0d7863a0e3c5481b51eb76fcc526c5c", "sha256": "1ce1b279d5c7fc41fa44af70b7b339aa6f8603ce980167cce281160587796e25" }, "downloads": -1, "filename": "known_side_effects-0.1.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "f0d7863a0e3c5481b51eb76fcc526c5c", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 12007, "upload_time": "2019-07-28T15:49:05", "url": "https://files.pythonhosted.org/packages/ac/f9/fc64fb88b7cc497a834e41d26fc5e8dfc81fe94b2919a756915ed68c226f/known_side_effects-0.1.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "365c982cb48d8ffba96cf78c3e7c8b52", "sha256": "7c118f5563697eb13766ca9f3ab83897494562cc8b4634a1ef9a1404ad8f4267" }, "downloads": -1, "filename": "known_side_effects-0.1.0.tar.gz", "has_sig": false, "md5_digest": "365c982cb48d8ffba96cf78c3e7c8b52", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5787, "upload_time": "2019-07-28T15:49:07", "url": "https://files.pythonhosted.org/packages/81/93/6a47bfd07fb8a189856a6b8ecec25225805e7808f66c8cf4590dc08d2519/known_side_effects-0.1.0.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "837e69362746d6164b39bc27171e7915", "sha256": "5a075dd6affe94d42af4a6d02c71ff821ed11e7129d1df6962f012984a42bf2b" }, "downloads": -1, "filename": "known_side_effects-0.1.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "837e69362746d6164b39bc27171e7915", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 12055, "upload_time": "2019-08-02T14:48:37", "url": "https://files.pythonhosted.org/packages/e0/24/29977e63a29b238795f7319bf61940822d7f917a8a42aa3d04f816e20002/known_side_effects-0.1.1-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "9131de6f544b90f7129a23bc6af219c6", "sha256": "c06038be7efc3414a0ccf6c3ca8ff70234cb7e4a10f8521cf8da5298e2790bf5" }, "downloads": -1, "filename": "known_side_effects-0.1.1.tar.gz", "has_sig": false, "md5_digest": "9131de6f544b90f7129a23bc6af219c6", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5822, "upload_time": "2019-08-02T14:48:39", "url": "https://files.pythonhosted.org/packages/bb/8e/c48be94c414062bbaa350533104544c4ea109becaa9d2d8da44727ca63e5/known_side_effects-0.1.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "837e69362746d6164b39bc27171e7915", "sha256": "5a075dd6affe94d42af4a6d02c71ff821ed11e7129d1df6962f012984a42bf2b" }, "downloads": -1, "filename": "known_side_effects-0.1.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "837e69362746d6164b39bc27171e7915", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 12055, "upload_time": "2019-08-02T14:48:37", "url": "https://files.pythonhosted.org/packages/e0/24/29977e63a29b238795f7319bf61940822d7f917a8a42aa3d04f816e20002/known_side_effects-0.1.1-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "9131de6f544b90f7129a23bc6af219c6", "sha256": "c06038be7efc3414a0ccf6c3ca8ff70234cb7e4a10f8521cf8da5298e2790bf5" }, "downloads": -1, "filename": "known_side_effects-0.1.1.tar.gz", "has_sig": false, "md5_digest": "9131de6f544b90f7129a23bc6af219c6", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5822, "upload_time": "2019-08-02T14:48:39", "url": "https://files.pythonhosted.org/packages/bb/8e/c48be94c414062bbaa350533104544c4ea109becaa9d2d8da44727ca63e5/known_side_effects-0.1.1.tar.gz" } ] }