{ "info": { "author": "Peter Kogan", "author_email": "kogan.peter@gmail.com", "bugtrack_url": null, "classifiers": [ "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.3" ], "description": "# Mock Generator\nA tool to generate the basic mocks and asserts for faster unit testing. \n\n## Introduction\nA typical unit test looks like this (AAA pattern):\n* Arrange \u2013 Setup and prepare the various objects and prerequisites.\n* Act \u2013 Invoke the tested code by calling the tested function for example.\n* Assert \u2013 Verify the outcome. This can be the return value of the tested \nfunction and/or some side effects.\n\nAs it turns out, much of the time spent on doing unit tests is wasted on wiring\nthe various modules and functions and only a fraction of the time is spent on\nthe actual logic of the test. The `Arrange` and `Assert` sections are notorious\nin that regard. \n\nThis tool is meant to save you much of the time and effort of generating \nboilerplates, by generating the `Arrange` and `Assert` sections. \nThe generated code can then be used as is, or altered according to your needs.\n\n## Usage\nNote: All examples assume the \n[pytest-mock](https://pypi.org/project/pytest-mock/) which is a fixture for\n[pytest](https://pypi.org/project/pytest/). \n\n### Simple example\nLet's start with a simple code example. Say you have a module `os_wrapper.py`:\n```python\nimport os \n\ndef os_remove_wrap(filename):\n os.remove(filename)\n```\nYou would like to test that the `os.remove` function is called with the same\nvalue sent to your wrapping function. The test would look something like this:\n```python\ndef test_os_remove_wrap(mocker):\n # Arrange: setup any mocks to avoid deleting actual files\n\n # Act: invoking the tested code\n os_wrapper.os_remove_wrap('/my/path/to/file.txt')\n\n # Assert: verifying that the original os.remove function was called\n```\n\n#### Generating the Arrange section\nThe following code sends the tested module to the tool, along with instructions \nwhich indicate the desired testing framework and which mocks to generate\n(we would like to use pytest-mock fixture and only mock the referenced \nmodules): \n\n```python\nimport os_wrapper\nfrom mock_autogen.pytest_mocker import PytestMocker\n\ngenerated_mocks = PytestMocker(os_wrapper).mock_modules().generate() \n```\nThe `generated_mocks` variable now has the desired code: \n```python\n# mocked modules\nmock_os = mocker.MagicMock(name='os')\nmocker.patch('os_wrapper.os', new=mock_os)\n```\nSimply copy the code and place it in your test, before the `Act` section: \n```python\nimport os_wrapper\n\ndef test_os_remove_wrap(mocker):\n # Arrange: setup any mocks to avoid deleting actual files\n # auto generated code\n # mocked modules\n mock_os = mocker.MagicMock(name='os')\n mocker.patch('os_wrapper.os', new=mock_os)\n\n # Act: invoking the tested code\n os_wrapper.os_remove_wrap('/my/path/to/file.txt')\n\n # Assert: verifying that the original os.remove function was called\n```\n\n#### Generating the Assert section\nNow it's time to add the asserts. Add the following code right after the Act \nstep:\n```python\nimport mock_autogen\n\ngenerated_asserts = mock_autogen.generator.generate_asserts(mock_os)\n```\nThe `mock_os` is the mocked object you created earlier.\n\nThe `generated_asserts` variable now has the desired code: \n```python\nmock_os.remove.assert_called_once_with('/my/path/to/file.txt')\n```\nPlace that code right after the act phase and you're done!\n\nThe complete test function:\n```python\nimport os_wrapper\n\ndef test_os_remove_wrap(mocker):\n # Arrange: setup any mocks to avoid deleting actual files\n # auto generated code\n # mocked modules\n mock_os = mocker.MagicMock(name='os')\n mocker.patch('os_wrapper.os', new=mock_os)\n\n # Act: invoking the tested code\n os_wrapper.os_remove_wrap('/my/path/to/file.txt')\n\n # Assert: verifying that the original os.remove function was called\n # auto generated code\n mock_os.remove.assert_called_once_with('/my/path/to/file.txt')\n```\nAs can be seen, most of the code was autogenerated so you can focus on the Act.\n\n### Complex example\nThe previous example was meant to demonstrate how to use the tool. If you have\nexperience with pytest-mock than you could have probably come up with the same\nboilerplate code by yourself in a reasonable time. The next example requires \nthe exact same steps to invoke the tool as before, but the benefit is much \ngreater. \n\nLet's assume you have a module `zip_writer.py` which holds a function to\nprocess a string sent to it and then add it to a zip file:\n```python\nimport zipfile\n\ndef process_and_zip(zip_path, file_name, contents):\n processed_contents = \"processed \" + contents # some complex logic\n with zipfile.ZipFile(zip_path, 'w') as zip_container:\n zip_container.writestr(file_name, processed_contents)\n```\nAlthough this is a very short function, which does not do anything complex, \nwriting the test code takes a lot of time. It's the fact that the function uses\na context manager makes the testing more complex than it should be. \n\nSince the process of generating the test code is the same as in the previous \nexample, there is no need to repeat it. Let's look at the complete code:\n```python\nimport zip_writer\n\ndef test_process_and_zip(mocker):\n # Arrange: auto generated code \n mock_zipfile = mocker.MagicMock(name='zipfile')\n mocker.patch('tests.sample.code.tested_module.zipfile', new=mock_zipfile)\n\n # Act: invoking the tested code\n zip_writer.process_and_zip('/path/to.zip', 'in_zip.txt', 'foo bar')\n\n # Assert: auto generated code\n mock_zipfile.ZipFile.assert_called_once_with('/path/to.zip', 'w')\n mock_zipfile.ZipFile.return_value.__enter__.assert_called_once_with()\n mock_zipfile.ZipFile.return_value.__enter__.return_value.writestr. \\\n assert_called_once_with('in_zip.txt', 'processed foo bar')\n mock_zipfile.ZipFile.return_value.__exit__. \\\n assert_called_once_with(None, None, None)\n```\nLook at all the asserts. They are very useful: \n* Checking that we opened the zip file with the right parameters.\n* Checking that we wrote the correct data to the proper file.\n* And finally, ensuring that `__enter__` and `__exit__` are called, so there \nare no open file handles which could cause problems.\n\nCan you imagine the time it would have taken you to code this on your own?\n\n### What's Next\n#### Mocking Everything\nAfter you have followed through this example, you can use the Mock Generator \nto **mock everything**. This way you can see all the possibilities of mocks. You \ncan also print the result right away, to avoid having to inspect variables. \nIt can look something like this:\n```python\nimport os_wrapper\nfrom mock_autogen.pytest_mocker import PytestMocker\n\nprint(PytestMocker(os_wrapper).mock_everything().generate()) \n```\nWhat you would get is:\n```python\n# mocked modules\nmock_os = mocker.MagicMock(name='os')\nmocker.patch('os_wrapper.os', new=mock_os)\n# mocked functions\nmock_os_remove_wrap = mocker.MagicMock(name='os_remove_wrap')\nmocker.patch('os_wrapper.os_remove', new=mock_os_remove_wrap)\n# calls to generate_asserts, put this after the 'act'\nimport mock_autogen\nprint(mock_autogen.generator.generate_asserts(mock_os, name='mock_os'))\nprint(mock_autogen.generator.generate_asserts(mock_os_remove_wrap, name='mock_os_remove_wrap'))\n```\nNotice the mocked functions section, it allows you to mock functions in\nthat model. This is useful when you're testing a function which uses\nanother function you would like to mock.\n\nYou even get the calls to generate the asserts prepared for you, place\nthis code after the act section as shown in the simple example. \n\n#### Asserting Existing Mocks\nAt times, you may be editing a legacy code already containing mocks, or\nyou may choose to write the mocks yourself, to gain some extra control.\n\nYou can use the mock generator to generate the asserts for you, for\nany given `Mock` or `MagicMock`, like so (replace `mockObj`): \n```python\n# calls to generate_asserts, put this after the 'act'\nimport mock_autogen.generator\nprint(mock_autogen.generator.generate_asserts(mockObj))\n```\n\n## Wrapping up\nI hope that by now you were convinced that this tool can save you a lot of \ntime. \n\nSee `tests` folder for additional usage examples like mocking classes and \ninstances, using fixtures to share mocks between tests and much more.\n\nIf you would like to contribute, I'm accepting pull requests :)\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/pksol/mock_autogen", "keywords": "", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "mock-generator", "package_url": "https://pypi.org/project/mock-generator/", "platform": "", "project_url": "https://pypi.org/project/mock-generator/", "project_urls": { "Homepage": "https://github.com/pksol/mock_autogen" }, "release_url": "https://pypi.org/project/mock-generator/0.2.2/", "requires_dist": [ "mock" ], "requires_python": ">=3.3", "summary": "Generate python mocks and assertions quickly", "version": "0.2.2" }, "last_serial": 5902172, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "a25d8d511aff447a7a499494960603ab", "sha256": "9605941d8d16971a35b0c6ed6e33b32e55f4e611bdd91874646cf5c58449517e" }, "downloads": -1, "filename": "mock_generator-0.1.0-py3-none-any.whl", "has_sig": false, "md5_digest": "a25d8d511aff447a7a499494960603ab", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 13881, "upload_time": "2019-07-28T09:18:38", "url": "https://files.pythonhosted.org/packages/dd/fd/c77bfc42d36f47ebc8fcd0700487c12b6a06695a328f160d8e187383f135/mock_generator-0.1.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "4e390182d2d51ed11517687310959726", "sha256": "b2a6ba2fe95555ef28d7fe87e52d75cb126ff46e03743f5fe69e80ed10d5e185" }, "downloads": -1, "filename": "mock-generator-0.1.0.tar.gz", "has_sig": false, "md5_digest": "4e390182d2d51ed11517687310959726", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 13720, "upload_time": "2019-07-28T09:18:40", "url": "https://files.pythonhosted.org/packages/1c/9f/5693d566b4f0b7ba56dd45b77af608808cee546428dfe1a574fc7c64d997/mock-generator-0.1.0.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "cec23b590b66047162c56abc89b7ddad", "sha256": "602c2f8fec8fe17240a1f3ad7eb9bac507e0a9b5c22d3206d34c02881c932bc7" }, "downloads": -1, "filename": "mock_generator-0.1.1-py3-none-any.whl", "has_sig": false, "md5_digest": "cec23b590b66047162c56abc89b7ddad", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 13939, "upload_time": "2019-07-28T11:16:44", "url": "https://files.pythonhosted.org/packages/65/08/5139eb148c37d7239c949f591bdc0bf7620219ad131dbe1fbd9cdd789a29/mock_generator-0.1.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "6ecc385109e392bc3e75038c5dd8f053", "sha256": "4d879c87df1f9602045395bd27429619f5284d0d17e3b8229b8224aef13c68ae" }, "downloads": -1, "filename": "mock-generator-0.1.1.tar.gz", "has_sig": false, "md5_digest": "6ecc385109e392bc3e75038c5dd8f053", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 13928, "upload_time": "2019-07-28T11:16:46", "url": "https://files.pythonhosted.org/packages/6b/db/d57c0ac36c48140b590189c95206c1a69186225c462e27f0f00e586794fb/mock-generator-0.1.1.tar.gz" } ], "0.2.0": [ { "comment_text": "", "digests": { "md5": "5a815e873b5e50c34bbfedab37b13249", "sha256": "f63ec0c2c5ae33495d18021bea25c0b72b1cbc6473fe10b6c0d50c54bf403ae6" }, "downloads": -1, "filename": "mock_generator-0.2.0-py3-none-any.whl", "has_sig": false, "md5_digest": "5a815e873b5e50c34bbfedab37b13249", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 13942, "upload_time": "2019-07-28T11:33:39", "url": "https://files.pythonhosted.org/packages/b1/d8/221e854db0b74aeda2fa33625dd8d39127db2056a88344c20069c947528a/mock_generator-0.2.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "78a82d57d6344c40f050830d2cabd379", "sha256": "271e2bbc37a3a07319bfccc702daed574e6c02118518f4f8bff74a0a2c93a835" }, "downloads": -1, "filename": "mock-generator-0.2.0.tar.gz", "has_sig": false, "md5_digest": "78a82d57d6344c40f050830d2cabd379", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 13922, "upload_time": "2019-07-28T11:33:41", "url": "https://files.pythonhosted.org/packages/ea/3a/1ccb69998bd7171ef0ec4fb11d6d67b6ae9e25e3f2be376cafd5c579baf4/mock-generator-0.2.0.tar.gz" } ], "0.2.1": [ { "comment_text": "", "digests": { "md5": "7aa84368e3e8fbf7134ab6f2eaefa081", "sha256": "44fa445a5ef158bc879a7c5ec703e5bf8ea750014e97c9a926fee4895cbbf7f1" }, "downloads": -1, "filename": "mock_generator-0.2.1-py3-none-any.whl", "has_sig": false, "md5_digest": "7aa84368e3e8fbf7134ab6f2eaefa081", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.3", "size": 16683, "upload_time": "2019-08-01T17:29:13", "url": "https://files.pythonhosted.org/packages/40/51/1ecca83252bcfb073ab89f4a70a1f3d7ed46456b95e6aeda976a8e46b14f/mock_generator-0.2.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "c02b4f9dc8890dabba46e8bb570f3ef3", "sha256": "409f6f2557412048eb0269659a695764d0064cdd86c0898d2ff6118858ad4322" }, "downloads": -1, "filename": "mock-generator-0.2.1.tar.gz", "has_sig": false, "md5_digest": "c02b4f9dc8890dabba46e8bb570f3ef3", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.3", "size": 15475, "upload_time": "2019-08-01T17:29:16", "url": "https://files.pythonhosted.org/packages/85/4f/7f92cb7b52865be09e301efa2ab2642bc2379dc2b9aebae15fe923025752/mock-generator-0.2.1.tar.gz" } ], "0.2.2": [ { "comment_text": "", "digests": { "md5": "8e6b3bca756c80278c2c051de48966e0", "sha256": "e8f32cd5203ce5472cde91a8233ca773af50dbb9daaa2a9f5ec0092a65984f2f" }, "downloads": -1, "filename": "mock_generator-0.2.2-py3-none-any.whl", "has_sig": false, "md5_digest": "8e6b3bca756c80278c2c051de48966e0", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.3", "size": 16825, "upload_time": "2019-09-29T09:00:09", "url": "https://files.pythonhosted.org/packages/3e/be/e2ee3dbe924ad89db6f638ef24eaa96cd71c7f998957d1188f9d03436097/mock_generator-0.2.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "c03b32fb75dc0befd6600b16cf63f12f", "sha256": "da4e8146a9cfb003efbf9767eb1e9350613d0dc03fed62a3eb153fd434b993fc" }, "downloads": -1, "filename": "mock-generator-0.2.2.tar.gz", "has_sig": false, "md5_digest": "c03b32fb75dc0befd6600b16cf63f12f", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.3", "size": 15830, "upload_time": "2019-09-29T09:00:11", "url": "https://files.pythonhosted.org/packages/2a/93/8b91240cb4978d8172ff0222d41e852cc823c7b9eef0c9fb20b452535dfb/mock-generator-0.2.2.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "8e6b3bca756c80278c2c051de48966e0", "sha256": "e8f32cd5203ce5472cde91a8233ca773af50dbb9daaa2a9f5ec0092a65984f2f" }, "downloads": -1, "filename": "mock_generator-0.2.2-py3-none-any.whl", "has_sig": false, "md5_digest": "8e6b3bca756c80278c2c051de48966e0", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.3", "size": 16825, "upload_time": "2019-09-29T09:00:09", "url": "https://files.pythonhosted.org/packages/3e/be/e2ee3dbe924ad89db6f638ef24eaa96cd71c7f998957d1188f9d03436097/mock_generator-0.2.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "c03b32fb75dc0befd6600b16cf63f12f", "sha256": "da4e8146a9cfb003efbf9767eb1e9350613d0dc03fed62a3eb153fd434b993fc" }, "downloads": -1, "filename": "mock-generator-0.2.2.tar.gz", "has_sig": false, "md5_digest": "c03b32fb75dc0befd6600b16cf63f12f", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.3", "size": 15830, "upload_time": "2019-09-29T09:00:11", "url": "https://files.pythonhosted.org/packages/2a/93/8b91240cb4978d8172ff0222d41e852cc823c7b9eef0c9fb20b452535dfb/mock-generator-0.2.2.tar.gz" } ] }