pytest-mock-3.6.1/0000755000175100001710000000000014045040653014600 5ustar runnerdocker00000000000000pytest-mock-3.6.1/.github/0000755000175100001710000000000014045040653016140 5ustar runnerdocker00000000000000pytest-mock-3.6.1/.github/FUNDING.yml0000644000175100001710000000030414045040650017747 0ustar runnerdocker00000000000000# info: # * https://help.github.com/en/articles/displaying-a-sponsor-button-in-your-repository # * https://tidelift.com/subscription/how-to-connect-tidelift-with-github tidelift: pypi/pytest-mock pytest-mock-3.6.1/.github/workflows/0000755000175100001710000000000014045040653020175 5ustar runnerdocker00000000000000pytest-mock-3.6.1/.github/workflows/main.yml0000644000175100001710000000263214045040650021644 0ustar runnerdocker00000000000000name: build on: [push, pull_request] jobs: build: runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: python: ["3.6", "3.7", "3.8", "3.9"] os: [ubuntu-latest, windows-latest] include: - python: "3.6" tox_env: "py36" - python: "3.7" tox_env: "py37" - python: "3.8" tox_env: "py38" - python: "3.9" tox_env: "py39" steps: - uses: actions/checkout@v1 - name: Set up Python uses: actions/setup-python@v2 with: python-version: ${{ matrix.python }} - name: Install tox run: | python -m pip install --upgrade pip pip install tox - name: Test run: | tox -e ${{ matrix.tox_env }} deploy: if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags') runs-on: ubuntu-latest needs: build steps: - uses: actions/checkout@v1 - name: Set up Python uses: actions/setup-python@v1 with: python-version: "3.7" - name: Install wheel run: | python -m pip install --upgrade pip pip install wheel - name: Build package run: | python setup.py sdist bdist_wheel - name: Publish package to PyPI uses: pypa/gh-action-pypi-publish@master with: user: __token__ password: ${{ secrets.pypi_token }} pytest-mock-3.6.1/.gitignore0000644000175100001710000000116614045040650016571 0ustar runnerdocker00000000000000# Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] # C extensions *.so # Distribution / packaging .Python env/ bin/ build/ develop-eggs/ dist/ eggs/ lib/ lib64/ parts/ sdist/ var/ *.egg-info/ .installed.cfg *.egg* # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .coverage .cache .pytest_cache nosetests.xml coverage.xml # Translations *.mo # Mr Developer .mr.developer.cfg .project .pydevproject # Rope .ropeproject # Django stuff: *.log *.pot # Sphinx documentation docs/_build/ # Virtual Envs .env* # IDE .idea .vscode /src/pytest_mock/_version.py pytest-mock-3.6.1/.pre-commit-config.yaml0000644000175100001710000000167514045040650021067 0ustar runnerdocker00000000000000exclude: '^($|.*\.bin)' repos: - repo: https://github.com/psf/black rev: 21.4b2 hooks: - id: black args: [--safe, --quiet] - repo: https://github.com/pre-commit/pre-commit-hooks rev: v3.4.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer - repo: local hooks: - id: rst name: rst entry: rst-lint --encoding utf-8 files: ^(CHANGELOG.rst|README.rst|HOWTORELEASE.rst|changelog/.*)$ language: python additional_dependencies: [pygments, restructuredtext_lint] - repo: https://github.com/asottile/reorder_python_imports rev: v2.5.0 hooks: - id: reorder-python-imports args: ['--application-directories=.:src'] - repo: https://github.com/pre-commit/mirrors-mypy rev: v0.812 # NOTE: keep this in sync with tox.ini hooks: - id: mypy files: ^(src|tests) args: [] additional_dependencies: [pytest>=6] pytest-mock-3.6.1/CHANGELOG.rst0000644000175100001710000004557414045040650016635 0ustar runnerdocker000000000000003.6.1 (2021-05-06) ------------------ * Fix ``mocker.resetall()`` when using ``mocker.spy()`` (`#237`_). Thanks `@blaxter`_ for the report and `@shadycuz`_ for the PR. .. _@blaxter: https://github.com/blaxter .. _@shadycuz: https://github.com/shadycuz .. _#237: https://github.com/pytest-dev/pytest-mock/issues/237 3.6.0 (2021-04-24) ------------------ * pytest-mock no longer supports Python 3.5. * Correct type annotations for ``mocker.patch.object`` to also include the string form. Thanks `@plannigan`_ for the PR (`#235`_). * ``reset_all`` now supports ``return_value`` and ``side_effect`` keyword arguments. Thanks `@alex-marty`_ for the PR (`#214`_). .. _@alex-marty: https://github.com/alex-marty .. _@plannigan: https://github.com/plannigan .. _#214: https://github.com/pytest-dev/pytest-mock/pull/214 .. _#235: https://github.com/pytest-dev/pytest-mock/pull/235 3.5.1 (2021-01-10) ------------------ * Use ``inspect.getattr_static`` instead of resorting to ``object.__getattribute__`` magic. This should better comply with objects which implement a custom descriptor protocol. Thanks `@yesthesoup`_ for the PR (`#224`_). .. _@yesthesoup: https://github.com/yesthesoup .. _#224: https://github.com/pytest-dev/pytest-mock/pull/224 3.5.0 (2021-01-04) ------------------ * Now all patch functions will emit a warning instead of raising a ``ValueError`` when used as a context-manager. Thanks `@iforapsy`_ for the PR (`#221`_). * Additionally, ``mocker.patch.context_manager`` is available when the user intends to mock a context manager (for example ``threading.Lock`` object), which will not emit that warning. .. _@iforapsy: https://github.com/iforapsy .. _#221: https://github.com/pytest-dev/pytest-mock/pull/221 3.4.0 (2020-12-15) ------------------ * Add `mock.seal` alias to the `mocker` fixture (`#211`_). Thanks `@coiax`_ for the PR. * Fixed spying on exceptions not covered by the ``Exception`` superclass (`#215`_), like ``KeyboardInterrupt`` -- PR `#216`_ by `@webknjaz`_. Before the fix, both ``spy_return`` and ``spy_exception`` were always assigned to ``None`` whenever such an exception happened. And after this fix, ``spy_exception`` is set to a correct value of an exception that has actually happened. .. _@coiax: https://github.com/coiax .. _@webknjaz: https://github.com/sponsors/webknjaz .. _#211: https://github.com/pytest-dev/pytest-mock/pull/211 .. _#215: https://github.com/pytest-dev/pytest-mock/issues/215 .. _#216: https://github.com/pytest-dev/pytest-mock/pull/216 3.3.1 (2020-08-24) ------------------ * Introduce ``MockFixture`` as an alias to ``MockerFixture``. Before ``3.3.0``, the fixture class was named ``MockFixture``, but was renamed to ``MockerFixture`` to better match the ``mocker`` fixture. While not officially part of the API, it was later discovered that this broke the code of some users which already imported ``pytest_mock.MockFixture`` for type annotations, so we decided to reintroduce the name as an alias. Note however that this is just a stop gap measure, and new code should use ``MockerFixture`` for type annotations. * Improved typing for ``MockerFixture.patch`` (`#201`_). Thanks `@srittau`_ for the PR. .. _@srittau: https://github.com/srittau .. _#201: https://github.com/pytest-dev/pytest-mock/pull/201 3.3.0 (2020-08-21) ------------------ * ``pytest-mock`` now includes inline type annotations and exposes them to user programs. The ``mocker`` fixture returns ``pytest_mock.MockerFixture``, which can be used to annotate your tests: .. code-block:: python from pytest_mock import MockerFixture def test_foo(mocker: MockerFixture) -> None: ... The type annotations were developed against mypy version ``0.782``, the minimum version supported at the moment. If you run into an error that you believe to be incorrect, please open an issue. Many thanks to `@staticdev`_ for providing the initial patch (`#199`_). .. _@staticdev: https://github.com/staticdev .. _#199: https://github.com/pytest-dev/pytest-mock/pull/199 3.2.0 (2020-07-11) ------------------ * `AsyncMock `__ is now exposed in ``mocker`` and supports provides assertion introspection similar to ``Mock`` objects. Added by `@tirkarthi`_ in `#197`_. .. _@tirkarthi: https://github.com/tirkarthi .. _#197: https://github.com/pytest-dev/pytest-mock/pull/197 3.1.1 (2020-05-31) ------------------ * Fixed performance regression caused by the ``ValueError`` raised when ``mocker`` is used as context manager (`#191`_). .. _#191: https://github.com/pytest-dev/pytest-mock/issues/191 3.1.0 (2020-04-18) ------------------ * New mocker fixtures added that allow using mocking functionality in other scopes: * ``class_mocker`` * ``module_mocker`` * ``package_mocker`` * ``session_mocker`` Added by `@scorphus`_ in `#182`_. .. _@scorphus: https://github.com/scorphus .. _#182: https://github.com/pytest-dev/pytest-mock/pull/182 3.0.0 (2020-03-31) ------------------ * Python 2.7 and 3.4 are no longer supported. Users using ``pip 9`` or later will install a compatible version automatically. * ``mocker.spy`` now also works with ``async def`` functions (`#179`_). Thanks `@frankie567`_ for the PR! .. _#179: https://github.com/pytest-dev/pytest-mock/issues/179 .. _@frankie567: https://github.com/frankie567 2.0.0 (2020-01-04) ------------------ Breaking Changes ++++++++++++++++ * ``mocker.spy`` attributes for tracking returned values and raised exceptions of its spied functions are now called ``spy_return`` and ``spy_exception``, instead of reusing the existing ``MagicMock`` attributes ``return_value`` and ``side_effect``. Version ``1.13`` introduced a serious regression: after a spied function using ``mocker.spy`` raises an exception, further calls to the spy will not call the spied function, always raising the first exception instead: assigning to ``side_effect`` causes ``unittest.mock`` to behave this way (`#175`_). * The deprecated ``mock`` alias to the ``mocker`` fixture has finally been removed. .. _#175: https://github.com/pytest-dev/pytest-mock/issues/175 1.13.0 (2019-12-05) ------------------- * The object returned by ``mocker.spy`` now also tracks any side effect of the spied method/function. 1.12.1 (2019-11-20) ------------------- * Fix error if ``mocker.patch`` is used in code where the source file is not available, for example stale ``.pyc`` files (`#169`_). .. _#169: https://github.com/pytest-dev/pytest-mock/issues/169#issuecomment-555729265 1.12.0 (2019-11-19) ------------------- * Now all patch functions also raise a ``ValueError`` when used as a context-manager. Thanks `@AlexGascon`_ for the PR (`#168`_). .. _@AlexGascon: https://github.com/AlexGascon .. _#168: https://github.com/pytest-dev/pytest-mock/pull/168 1.11.2 (2019-10-19) ------------------- * The *pytest introspection follows* message is no longer shown if there is no pytest introspection (`#154`_). Thanks `@The-Compiler`_ for the report. * ``mocker`` now raises a ``ValueError`` when used as a context-manager. Thanks `@binarymason`_ for the PR (`#165`_). .. _#154: https://github.com/pytest-dev/pytest-mock/issues/154 .. _#165: https://github.com/pytest-dev/pytest-mock/pull/165 .. _@binarymason: https://github.com/binarymason 1.11.1 (2019-10-04) ------------------- * Fix ``mocker.spy`` on Python 2 when used on non-function objects which implement ``__call__`` (`#157`_). Thanks `@pbasista`_ for the report. .. _#157: https://github.com/pytest-dev/pytest-mock/issues/157 .. _@pbasista: https://github.com/pbasista 1.11.0 ------ * The object returned by ``mocker.spy`` now also tracks the return value of the spied method/function. 1.10.4 ------ * Fix plugin when 'terminal' plugin is disabled 1.10.3 ------ * Fix test suite in Python 3.8. Thanks `@hroncok`_ for the report and `@blueyed`_ for the PR (`#140`_). .. _#140: https://github.com/pytest-dev/pytest-mock/pull/140 .. _@hroncok: https://github.com/hroncok 1.10.2 ------ * Fix bug at the end of the test session when a call to ``patch.stopall`` is done explicitly by user code. Thanks `@craiga`_ for the report (`#137`_). .. _#137: https://github.com/pytest-dev/pytest-mock/issues/137 .. _@craiga: https://github.com/craiga 1.10.1 ------ * Fix broken links and update README. Also the code is now formatted using `black `__. 1.10.0 ------ * Add support for the recently added ``assert_called`` method in Python 3.6 and ``mock-2.0``. Thanks `@rouge8`_ for the PR (`#115`_). .. _#115: https://github.com/pytest-dev/pytest-mock/pull/115 1.9.0 ----- * Add support for the recently added ``assert_called_once`` method in Python 3.6 and ``mock-2.0``. Thanks `@rouge8`_ for the PR (`#113`_). .. _#113: https://github.com/pytest-dev/pytest-mock/pull/113 1.8.0 ----- * Add aliases for ``NonCallableMock`` and ``create_autospec`` to ``mocker``. Thanks `@mlhamel`_ for the PR (`#111`_). .. _#111: https://github.com/pytest-dev/pytest-mock/pull/111 1.7.1 ----- * Fix ``setup.py`` to correctly read the ``README.rst``. Thanks `@ghisvail`_ for the fix (`#107`_). .. _#107: https://github.com/pytest-dev/pytest-mock/issues/107 1.7.0 ----- **Incompatible change** * ``pytest-mock`` no longer supports Python 2.6 and Python 3.3, following the lead of ``pytest`` and other projects in the community. Thanks `@hugovk`_ for the PR (`#96`_). **Packaging** * Fix ``mock`` requirement in Python 2. Thanks `@ghisvail`_ for the report (`#101`_). **Internal** * Some tests in ``pytest-mock``'s suite are skipped if assertion rewriting is disabled (`#102`_). .. _@ghisvail: https://github.com/ghisvail .. _@hugovk: https://github.com/hugovk .. _#96: https://github.com/pytest-dev/pytest-mock/pull/96 .. _#101: https://github.com/pytest-dev/pytest-mock/issues/101 .. _#102: https://github.com/pytest-dev/pytest-mock/issues/102 1.6.3 ----- * Fix ``UnicodeDecodeError`` during assert introspection in ``assert_called_with`` in Python 2. Thanks `@AndreasHogstrom`_ for the report (`#91`_). .. _@AndreasHogstrom: https://github.com/AndreasHogstrom .. _#91: https://github.com/pytest-dev/pytest-mock/issues/91 1.6.2 ----- * Provide source package in ``tar.gz`` format and remove obsolete ``MANIFEST.in``. 1.6.1 ----- * Fix ``mocker.resetall()`` by ignoring mocker objects which don't have a ``resetall`` method, like for example ``patch.dict``. Thanks `@jdavisp3`_ for the PR (`#88`_). .. _@jdavisp3: https://github.com/jdavisp3 .. _#88: https://github.com/pytest-dev/pytest-mock/pull/88 1.6.0 ----- * The original assertions raised by the various ``Mock.assert_*`` methods now appear in the failure message, in addition to the message obtained from pytest introspection. Thanks `@quodlibetor`_ for the initial patch (`#79`_). .. _@quodlibetor: https://github.com/quodlibetor .. _#79: https://github.com/pytest-dev/pytest-mock/pull/79 1.5.0 ----- * New ``mocker.mock_module`` variable points to the underlying mock module being used (``unittest.mock`` or ``mock``). Thanks `@blueyed`_ for the request (`#71`_). .. _#71: https://github.com/pytest-dev/pytest-mock/pull/71 1.4.0 ----- * New configuration variable, ``mock_use_standalone_module`` (defaults to ``False``). This forces the plugin to import ``mock`` instead of ``unittest.mock`` on Python 3. This is useful to import a newer version than the one available in the Python distribution. * Previously the plugin would first try to import ``mock`` and fallback to ``unittest.mock`` in case of an ``ImportError``, but this behavior has been removed because it could hide hard to debug import errors (`#68`_). * Now ``mock`` (Python 2) and ``unittest.mock`` (Python 3) are lazy-loaded to make it possible to implement the new ``mock_use_standlone_module`` configuration option. As a consequence of this the undocumented ``pytest_mock.mock_module`` variable, which pointed to the actual mock module being used by the plugin, has been removed. * `DEFAULT `_ is now available from the ``mocker`` fixture. .. _#68: https://github.com/pytest-dev/pytest-mock/issues/68 1.3.0 ----- * Add support for Python 3.6. Thanks `@hackebrot`_ for the report (`#59`_). * ``mock.mock_open`` is now aliased as ``mocker.mock_open`` for convenience. Thanks `@pokidovea`_ for the PR (`#66`_). .. _@hackebrot: https://github.com/hackebrot .. _@pokidovea: https://github.com/pokidovea .. _#59: https://github.com/pytest-dev/pytest-mock/issues/59 .. _#66: https://github.com/pytest-dev/pytest-mock/pull/66 1.2 --- * Try to import ``mock`` first instead of ``unittest.mock``. This gives the user flexibility to install a newer ``mock`` version from PyPI instead of using the one available in the Python distribution. Thanks `@wcooley`_ for the PR (`#54`_). * ``mock.sentinel`` is now aliased as ``mocker.sentinel`` for convenience. Thanks `@kjwilcox`_ for the PR (`#56`_). .. _@wcooley: https://github.com/wcooley .. _@kjwilcox: https://github.com/kjwilcox .. _#54: https://github.com/pytest-dev/pytest-mock/issues/54 .. _#56: https://github.com/pytest-dev/pytest-mock/pull/56 1.1 --- * From this version onward, ``pytest-mock`` is licensed under the `MIT`_ license (`#45`_). * Now the plugin also adds introspection information on differing call arguments when calling helper methods such as ``assert_called_once_with``. The extra introspection information is similar to pytest's and can be disabled with the ``mock_traceback_monkeypatch`` option. Thanks `@asfaltboy`_ for the PR (`#36`_). * ``mocker.stub()`` now allows passing in the name for the constructed `Mock `_ object instead of having to set it using the internal ``_mock_name`` attribute directly. This is useful for debugging as the name is used in the mock's ``repr`` string as well as related assertion failure messages. Thanks `@jurko-gospodnetic`_ for the PR (`#40`_). * Monkey patching ``mock`` module for friendlier tracebacks is automatically disabled with the ``--tb=native`` option. The underlying mechanism used to suppress traceback entries from ``mock`` module does not work with that option anyway plus it generates confusing messages on Python 3.5 due to exception chaining (`#44`_). Thanks `@blueyed`_ for the report. * ``mock.call`` is now aliased as ``mocker.call`` for convenience. Thanks `@jhermann`_ for the PR (`#49`_). .. _@jurko-gospodnetic: https://github.com/jurko-gospodnetic .. _@asfaltboy: https://github.com/asfaltboy .. _@jhermann: https://github.com/jhermann .. _#45: https://github.com/pytest-dev/pytest-mock/issues/45 .. _#36: https://github.com/pytest-dev/pytest-mock/issues/36 .. _#40: https://github.com/pytest-dev/pytest-mock/issues/40 .. _#44: https://github.com/pytest-dev/pytest-mock/issues/44 .. _#49: https://github.com/pytest-dev/pytest-mock/issues/49 .. _MIT: https://github.com/pytest-dev/pytest-mock/blob/master/LICENSE 1.0 --- * Fix AttributeError with ``mocker.spy`` when spying on inherited methods (`#42`_). Thanks `@blueyed`_ for the PR. .. _@blueyed: https://github.com/blueyed .. _#42: https://github.com/pytest-dev/pytest-mock/issues/42 0.11.0 ------ * `PropertyMock `_ is now accessible from ``mocker``. Thanks `@satyrius`_ for the PR (`#32`_). * Fix regression using one of the ``assert_*`` methods in patched functions which receive a parameter named ``method``. Thanks `@sagarchalise`_ for the report (`#31`_). .. _@sagarchalise: https://github.com/sagarchalise .. _@satyrius: https://github.com/satyrius .. _#31: https://github.com/pytest-dev/pytest-mock/issues/31 .. _#32: https://github.com/pytest-dev/pytest-mock/issues/32 0.10.1 ------ * Fix regression in frozen tests due to ``distutils`` import dependency. Thanks `@The-Compiler`_ for the report (`#29`_). * Fix regression when using ``pytest-mock`` with ``pytest-2.7.X``. Thanks `@akscram`_ for the report (`#28`_). .. _@akscram: https://github.com/Chronial .. _#28: https://github.com/pytest-dev/pytest-mock/issues/28 .. _#29: https://github.com/pytest-dev/pytest-mock/issues/29 0.10 ---- * ``pytest-mock`` now monkeypatches the ``mock`` library to improve pytest output for failures of mock call assertions like ``Mock.assert_called_with()``. Thanks to `@Chronial`_ for idea and PR (`#26`_, `#27`_)! .. _@Chronial: https://github.com/Chronial .. _#26: https://github.com/pytest-dev/pytest-mock/issues/26 .. _#27: https://github.com/pytest-dev/pytest-mock/issues/27 0.9.0 ----- * New ``mocker.resetall`` function, which calls ``reset_mock()`` in all mocked objects up to that point. Thanks to `@mathrick`_ for the PR! 0.8.1 ----- * ``pytest-mock`` is now also available as a wheel. Thanks `@rouge8`_ for the PR! 0.8.0 ----- * ``mock.ANY`` is now accessible from the mocker fixture (`#17`_), thanks `@tigarmo`_ for the PR! .. _#17: https://github.com/pytest-dev/pytest-qt/issues/17 0.7.0 ----- Thanks to `@fogo`_, mocker.spy can now prey upon staticmethods and classmethods. :smile: 0.6.0 ----- * Two new auxiliary methods, ``spy`` and ``stub``. See ``README`` for usage. (Thanks `@fogo`_ for complete PR!) 0.5.0 ----- * ``Mock`` and ``MagicMock`` are now accessible from the ``mocker`` fixture, many thanks to `@marcwebbie`_ for the complete PR! 0.4.3 ----- * ``mocker`` fixture now returns the same object (`#8`_). Many thanks to `@RonnyPfannschmidt`_ for the PR! .. _#8: https://github.com/pytest-dev/pytest-qt/issues/8 0.4.2 ----- * Small fix, no longer using wheel as an alternate package since it conditionally depends on mock module based on Python version, as Python >= 3.3 already includes ``unittest.mock``. Many thanks to `@The-Compiler`_ for letting me know and providing a PR with the fix! 0.4.1 ----- * Small release that just uses ``pytest_mock`` as the name of the plugin, instead of ``pytest-mock``: this makes it simple to depend on this plugin explicitly using ``pytest_plugins`` module variable mechanism. 0.4.0 ----- * Changed fixture name from ``mock`` into ``mocker`` because it conflicted with the actual mock module, which made using it awkward when access to both the module and the fixture were required within a test. Thanks `@kmosher`_ for request and discussion in `#4`_. :smile: .. _#4: https://github.com/pytest-dev/pytest-qt/issues/4 0.3.0 ----- * Fixed bug `#2`_, where a patch would not be uninstalled correctly after patching the same object twice. 0.2.0 ----- * Added ``patch.dict`` support. 0.1.0 ----- First release. .. _#2: https://github.com/pytest-dev/pytest-qt/issues/2 .. _@fogo: https://github.com/fogo .. _@kmosher: https://github.com/kmosher .. _@marcwebbie: https://github.com/marcwebbie .. _@mathrick: https://github.com/mathrick .. _@mlhamel: https://github.com/mlhamel .. _@RonnyPfannschmidt: https://github.com/RonnyPfannschmidt .. _@rouge8: https://github.com/rouge8 .. _@The-Compiler: https://github.com/The-Compiler .. _@tigarmo: https://github.com/tigarmo pytest-mock-3.6.1/HOWTORELEASE.rst0000644000175100001710000000037114045040650017231 0ustar runnerdocker00000000000000Here are the steps on how to make a new release. 1. Create a ``release-VERSION`` branch from ``upstream/master``. 2. Update ``CHANGELOG.rst``. 3. Push a branch with the changes. 4. Once all builds pass, push a tag to ``upstream``. 5. Merge the PR. pytest-mock-3.6.1/LICENSE0000644000175100001710000000206314045040650015603 0ustar runnerdocker00000000000000MIT License Copyright (c) [2016] [Bruno Oliveira] Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. pytest-mock-3.6.1/PKG-INFO0000644000175100001710000004245414045040653015706 0ustar runnerdocker00000000000000Metadata-Version: 2.1 Name: pytest-mock Version: 3.6.1 Summary: Thin-wrapper around the mock package for easier use with pytest Home-page: https://github.com/pytest-dev/pytest-mock/ Author: Bruno Oliveira Author-email: nicoddemus@gmail.com License: MIT Description: =========== pytest-mock =========== This plugin provides a ``mocker`` fixture which is a thin-wrapper around the patching API provided by the `mock package `_: .. code-block:: python import os class UnixFS: @staticmethod def rm(filename): os.remove(filename) def test_unix_fs(mocker): mocker.patch('os.remove') UnixFS.rm('file') os.remove.assert_called_once_with('file') Besides undoing the mocking automatically after the end of the test, it also provides other nice utilities such as ``spy`` and ``stub``, and uses pytest introspection when comparing calls. |python| |version| |anaconda| |ci| |coverage| |black| |pre-commit| .. |version| image:: http://img.shields.io/pypi/v/pytest-mock.svg :target: https://pypi.python.org/pypi/pytest-mock .. |anaconda| image:: https://img.shields.io/conda/vn/conda-forge/pytest-mock.svg :target: https://anaconda.org/conda-forge/pytest-mock .. |ci| image:: https://github.com/pytest-dev/pytest-mock/workflows/build/badge.svg :target: https://github.com/pytest-dev/pytest-mock/actions .. |coverage| image:: https://coveralls.io/repos/github/pytest-dev/pytest-mock/badge.svg?branch=master :target: https://coveralls.io/github/pytest-dev/pytest-mock?branch=master .. |python| image:: https://img.shields.io/pypi/pyversions/pytest-mock.svg :target: https://pypi.python.org/pypi/pytest-mock/ .. |black| image:: https://img.shields.io/badge/code%20style-black-000000.svg :target: https://github.com/ambv/black .. |pre-commit| image:: https://results.pre-commit.ci/badge/github/pytest-dev/pytest-mock/master.svg :target: https://results.pre-commit.ci/latest/github/pytest-dev/pytest-mock/master `Professionally supported pytest-mock is now available `_ Usage ===== The ``mocker`` fixture has the same API as `mock.patch `_, supporting the same arguments: .. code-block:: python def test_foo(mocker): # all valid calls mocker.patch('os.remove') mocker.patch.object(os, 'listdir', autospec=True) mocked_isfile = mocker.patch('os.path.isfile') The supported methods are: * `mocker.patch `_ * `mocker.patch.object `_ * `mocker.patch.multiple `_ * `mocker.patch.dict `_ * `mocker.stopall `_ * ``mocker.resetall()``: calls `reset_mock() `_ in all mocked objects up to this point. Also, as a convenience, these names from the ``mock`` module are accessible directly from ``mocker``: * `Mock `_ * `MagicMock `_ * `PropertyMock `_ * `ANY `_ * `DEFAULT `_ *(Version 1.4)* * `call `_ *(Version 1.1)* * `sentinel `_ *(Version 1.2)* * `mock_open `_ * `seal `_ *(Version 3.4)* It is also possible to use mocking functionality from fixtures of other scopes using the appropriate mock fixture: * ``class_mocker`` * ``module_mocker`` * ``package_mocker`` * ``session_mocker`` Type Annotations ---------------- *New in version 3.3.0.* ``pytest-mock`` is fully type annotated, letting users use static type checkers to test their code. The ``mocker`` fixture returns ``pytest_mock.MockerFixture`` which can be used to annotate test functions: .. code-block:: python from pytest_mock import MockerFixture def test_foo(mocker: MockerFixture) -> None: ... The type annotations have been checked with ``mypy``, which is the only type checker supported at the moment; other type-checkers might work but are not currently tested. Spy --- The ``mocker.spy`` object acts exactly like the original method in all cases, except the spy also tracks function/method calls, return values and exceptions raised. .. code-block:: python def test_spy_method(mocker): class Foo(object): def bar(self, v): return v * 2 foo = Foo() spy = mocker.spy(foo, 'bar') assert foo.bar(21) == 42 spy.assert_called_once_with(21) assert spy.spy_return == 42 def test_spy_function(mocker): # mymodule declares `myfunction` which just returns 42 import mymodule spy = mocker.spy(mymodule, "myfunction") assert mymodule.myfunction() == 42 assert spy.call_count == 1 assert spy.spy_return == 42 The object returned by ``mocker.spy`` is a ``MagicMock`` object, so all standard checking functions are available (like ``assert_called_once_with`` or ``call_count`` in the examples above). In addition, spy objects contain two extra attributes: * ``spy_return``: contains the returned value of the spied function. * ``spy_exception``: contain the last exception value raised by the spied function/method when it was last called, or ``None`` if no exception was raised. Besides functions and normal methods, ``mocker.spy`` also works for class and static methods. As of version 3.0.0, ``mocker.spy`` also works with ``async def`` functions. .. note:: In versions earlier than ``2.0``, the attributes were called ``return_value`` and ``side_effect`` respectively, but due to incompatibilities with ``unittest.mock`` they had to be renamed (see `#175`_ for details). .. _#175: https://github.com/pytest-dev/pytest-mock/issues/175 Stub ---- The stub is a mock object that accepts any arguments and is useful to test callbacks. It may receive an optional name that is shown in its ``repr``, useful for debugging. .. code-block:: python def test_stub(mocker): def foo(on_something): on_something('foo', 'bar') stub = mocker.stub(name='on_something_stub') foo(stub) stub.assert_called_once_with('foo', 'bar') Improved reporting of mock call assertion errors ------------------------------------------------ This plugin monkeypatches the mock library to improve pytest output for failures of mock call assertions like ``Mock.assert_called_with()`` by hiding internal traceback entries from the ``mock`` module. It also adds introspection information on differing call arguments when calling the helper methods. This features catches `AssertionError` raised in the method, and uses pytest's own `advanced assertions`_ to return a better diff:: mocker = def test(mocker): m = mocker.Mock() m('fo') > m.assert_called_once_with('', bar=4) E AssertionError: Expected call: mock('', bar=4) E Actual call: mock('fo') E E pytest introspection follows: E E Args: E assert ('fo',) == ('',) E At index 0 diff: 'fo' != '' E Use -v to get the full diff E Kwargs: E assert {} == {'bar': 4} E Right contains more items: E {'bar': 4} E Use -v to get the full diff test_foo.py:6: AssertionError ========================== 1 failed in 0.03 seconds =========================== This is useful when asserting mock calls with many/nested arguments and trying to quickly see the difference. This feature is probably safe, but if you encounter any problems it can be disabled in your ``pytest.ini`` file: .. code-block:: ini [pytest] mock_traceback_monkeypatch = false Note that this feature is automatically disabled with the ``--tb=native`` option. The underlying mechanism used to suppress traceback entries from ``mock`` module does not work with that option anyway plus it generates confusing messages on Python 3.5 due to exception chaining .. _advanced assertions: http://docs.pytest.org/en/stable/assert.html Use standalone "mock" package ----------------------------- *New in version 1.4.0.* Python 3 users might want to use a newest version of the ``mock`` package as published on PyPI than the one that comes with the Python distribution. .. code-block:: ini [pytest] mock_use_standalone_module = true This will force the plugin to import ``mock`` instead of the ``unittest.mock`` module bundled with Python 3.4+. Note that this option is only used in Python 3+, as Python 2 users only have the option to use the ``mock`` package from PyPI anyway. Note about usage as context manager ----------------------------------- Although mocker's API is intentionally the same as ``mock.patch``'s, its use as context manager and function decorator is **not** supported through the fixture: .. code-block:: python def test_context_manager(mocker): a = A() with mocker.patch.object(a, 'doIt', return_value=True, autospec=True): # DO NOT DO THIS assert a.doIt() == True The purpose of this plugin is to make the use of context managers and function decorators for mocking unnecessary, so it will emit a warning when used as such. If you really intend to mock a context manager, ``mocker.patch.context_manager`` exists which won't issue the above warning. Install ======= Install using `pip `_: .. code-block:: console $ pip install pytest-mock Changelog ========= Please consult the `changelog page`_. .. _changelog page: https://github.com/pytest-dev/pytest-mock/blob/master/CHANGELOG.rst Why bother with a plugin? ========================= There are a number of different ``patch`` usages in the standard ``mock`` API, but IMHO they don't scale very well when you have more than one or two patches to apply. It may lead to an excessive nesting of ``with`` statements, breaking the flow of the test: .. code-block:: python import mock def test_unix_fs(): with mock.patch('os.remove'): UnixFS.rm('file') os.remove.assert_called_once_with('file') with mock.patch('os.listdir'): assert UnixFS.ls('dir') == expected # ... with mock.patch('shutil.copy'): UnixFS.cp('src', 'dst') # ... One can use ``patch`` as a decorator to improve the flow of the test: .. code-block:: python @mock.patch('os.remove') @mock.patch('os.listdir') @mock.patch('shutil.copy') def test_unix_fs(mocked_copy, mocked_listdir, mocked_remove): UnixFS.rm('file') os.remove.assert_called_once_with('file') assert UnixFS.ls('dir') == expected # ... UnixFS.cp('src', 'dst') # ... But this poses a few disadvantages: - test functions must receive the mock objects as parameter, even if you don't plan to access them directly; also, order depends on the order of the decorated ``patch`` functions; - receiving the mocks as parameters doesn't mix nicely with pytest's approach of naming fixtures as parameters, or ``pytest.mark.parametrize``; - you can't easily undo the mocking during the test execution; An alternative is to use ``contextlib.ExitStack`` to stack the context managers in a single level of indentation to improve the flow of the test: .. code-block:: python import contextlib import mock def test_unix_fs(): with contextlib.ExitStack() as stack: stack.enter_context(mock.patch('os.remove')) UnixFS.rm('file') os.remove.assert_called_once_with('file') stack.enter_context(mock.patch('os.listdir')) assert UnixFS.ls('dir') == expected # ... stack.enter_context(mock.patch('shutil.copy')) UnixFS.cp('src', 'dst') # ... But this is arguably a little more complex than using ``pytest-mock``. Contributing ============ Contributions are welcome! After cloning the repository, create a virtual env and install ``pytest-mock`` in editable mode with ``dev`` extras: .. code-block:: console $ pip install --editable .[dev] $ pre-commit install Tests are run with ``tox``, you can run the baseline environments before submitting a PR: .. code-block:: console $ tox -e py38,linting Style checks and formatting are done automatically during commit courtesy of `pre-commit `_. License ======= Distributed under the terms of the `MIT`_ license. Security contact information ============================ To report a security vulnerability, please use the `Tidelift security contact `__. Tidelift will coordinate the fix and disclosure. .. _MIT: https://github.com/pytest-dev/pytest-mock/blob/master/LICENSE Keywords: pytest mock Platform: any Classifier: Development Status :: 5 - Production/Stable Classifier: Framework :: Pytest Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3 :: Only Classifier: Topic :: Software Development :: Testing Requires-Python: >=3.6 Provides-Extra: dev pytest-mock-3.6.1/README.rst0000644000175100001710000003232714045040650016273 0ustar runnerdocker00000000000000=========== pytest-mock =========== This plugin provides a ``mocker`` fixture which is a thin-wrapper around the patching API provided by the `mock package `_: .. code-block:: python import os class UnixFS: @staticmethod def rm(filename): os.remove(filename) def test_unix_fs(mocker): mocker.patch('os.remove') UnixFS.rm('file') os.remove.assert_called_once_with('file') Besides undoing the mocking automatically after the end of the test, it also provides other nice utilities such as ``spy`` and ``stub``, and uses pytest introspection when comparing calls. |python| |version| |anaconda| |ci| |coverage| |black| |pre-commit| .. |version| image:: http://img.shields.io/pypi/v/pytest-mock.svg :target: https://pypi.python.org/pypi/pytest-mock .. |anaconda| image:: https://img.shields.io/conda/vn/conda-forge/pytest-mock.svg :target: https://anaconda.org/conda-forge/pytest-mock .. |ci| image:: https://github.com/pytest-dev/pytest-mock/workflows/build/badge.svg :target: https://github.com/pytest-dev/pytest-mock/actions .. |coverage| image:: https://coveralls.io/repos/github/pytest-dev/pytest-mock/badge.svg?branch=master :target: https://coveralls.io/github/pytest-dev/pytest-mock?branch=master .. |python| image:: https://img.shields.io/pypi/pyversions/pytest-mock.svg :target: https://pypi.python.org/pypi/pytest-mock/ .. |black| image:: https://img.shields.io/badge/code%20style-black-000000.svg :target: https://github.com/ambv/black .. |pre-commit| image:: https://results.pre-commit.ci/badge/github/pytest-dev/pytest-mock/master.svg :target: https://results.pre-commit.ci/latest/github/pytest-dev/pytest-mock/master `Professionally supported pytest-mock is now available `_ Usage ===== The ``mocker`` fixture has the same API as `mock.patch `_, supporting the same arguments: .. code-block:: python def test_foo(mocker): # all valid calls mocker.patch('os.remove') mocker.patch.object(os, 'listdir', autospec=True) mocked_isfile = mocker.patch('os.path.isfile') The supported methods are: * `mocker.patch `_ * `mocker.patch.object `_ * `mocker.patch.multiple `_ * `mocker.patch.dict `_ * `mocker.stopall `_ * ``mocker.resetall()``: calls `reset_mock() `_ in all mocked objects up to this point. Also, as a convenience, these names from the ``mock`` module are accessible directly from ``mocker``: * `Mock `_ * `MagicMock `_ * `PropertyMock `_ * `ANY `_ * `DEFAULT `_ *(Version 1.4)* * `call `_ *(Version 1.1)* * `sentinel `_ *(Version 1.2)* * `mock_open `_ * `seal `_ *(Version 3.4)* It is also possible to use mocking functionality from fixtures of other scopes using the appropriate mock fixture: * ``class_mocker`` * ``module_mocker`` * ``package_mocker`` * ``session_mocker`` Type Annotations ---------------- *New in version 3.3.0.* ``pytest-mock`` is fully type annotated, letting users use static type checkers to test their code. The ``mocker`` fixture returns ``pytest_mock.MockerFixture`` which can be used to annotate test functions: .. code-block:: python from pytest_mock import MockerFixture def test_foo(mocker: MockerFixture) -> None: ... The type annotations have been checked with ``mypy``, which is the only type checker supported at the moment; other type-checkers might work but are not currently tested. Spy --- The ``mocker.spy`` object acts exactly like the original method in all cases, except the spy also tracks function/method calls, return values and exceptions raised. .. code-block:: python def test_spy_method(mocker): class Foo(object): def bar(self, v): return v * 2 foo = Foo() spy = mocker.spy(foo, 'bar') assert foo.bar(21) == 42 spy.assert_called_once_with(21) assert spy.spy_return == 42 def test_spy_function(mocker): # mymodule declares `myfunction` which just returns 42 import mymodule spy = mocker.spy(mymodule, "myfunction") assert mymodule.myfunction() == 42 assert spy.call_count == 1 assert spy.spy_return == 42 The object returned by ``mocker.spy`` is a ``MagicMock`` object, so all standard checking functions are available (like ``assert_called_once_with`` or ``call_count`` in the examples above). In addition, spy objects contain two extra attributes: * ``spy_return``: contains the returned value of the spied function. * ``spy_exception``: contain the last exception value raised by the spied function/method when it was last called, or ``None`` if no exception was raised. Besides functions and normal methods, ``mocker.spy`` also works for class and static methods. As of version 3.0.0, ``mocker.spy`` also works with ``async def`` functions. .. note:: In versions earlier than ``2.0``, the attributes were called ``return_value`` and ``side_effect`` respectively, but due to incompatibilities with ``unittest.mock`` they had to be renamed (see `#175`_ for details). .. _#175: https://github.com/pytest-dev/pytest-mock/issues/175 Stub ---- The stub is a mock object that accepts any arguments and is useful to test callbacks. It may receive an optional name that is shown in its ``repr``, useful for debugging. .. code-block:: python def test_stub(mocker): def foo(on_something): on_something('foo', 'bar') stub = mocker.stub(name='on_something_stub') foo(stub) stub.assert_called_once_with('foo', 'bar') Improved reporting of mock call assertion errors ------------------------------------------------ This plugin monkeypatches the mock library to improve pytest output for failures of mock call assertions like ``Mock.assert_called_with()`` by hiding internal traceback entries from the ``mock`` module. It also adds introspection information on differing call arguments when calling the helper methods. This features catches `AssertionError` raised in the method, and uses pytest's own `advanced assertions`_ to return a better diff:: mocker = def test(mocker): m = mocker.Mock() m('fo') > m.assert_called_once_with('', bar=4) E AssertionError: Expected call: mock('', bar=4) E Actual call: mock('fo') E E pytest introspection follows: E E Args: E assert ('fo',) == ('',) E At index 0 diff: 'fo' != '' E Use -v to get the full diff E Kwargs: E assert {} == {'bar': 4} E Right contains more items: E {'bar': 4} E Use -v to get the full diff test_foo.py:6: AssertionError ========================== 1 failed in 0.03 seconds =========================== This is useful when asserting mock calls with many/nested arguments and trying to quickly see the difference. This feature is probably safe, but if you encounter any problems it can be disabled in your ``pytest.ini`` file: .. code-block:: ini [pytest] mock_traceback_monkeypatch = false Note that this feature is automatically disabled with the ``--tb=native`` option. The underlying mechanism used to suppress traceback entries from ``mock`` module does not work with that option anyway plus it generates confusing messages on Python 3.5 due to exception chaining .. _advanced assertions: http://docs.pytest.org/en/stable/assert.html Use standalone "mock" package ----------------------------- *New in version 1.4.0.* Python 3 users might want to use a newest version of the ``mock`` package as published on PyPI than the one that comes with the Python distribution. .. code-block:: ini [pytest] mock_use_standalone_module = true This will force the plugin to import ``mock`` instead of the ``unittest.mock`` module bundled with Python 3.4+. Note that this option is only used in Python 3+, as Python 2 users only have the option to use the ``mock`` package from PyPI anyway. Note about usage as context manager ----------------------------------- Although mocker's API is intentionally the same as ``mock.patch``'s, its use as context manager and function decorator is **not** supported through the fixture: .. code-block:: python def test_context_manager(mocker): a = A() with mocker.patch.object(a, 'doIt', return_value=True, autospec=True): # DO NOT DO THIS assert a.doIt() == True The purpose of this plugin is to make the use of context managers and function decorators for mocking unnecessary, so it will emit a warning when used as such. If you really intend to mock a context manager, ``mocker.patch.context_manager`` exists which won't issue the above warning. Install ======= Install using `pip `_: .. code-block:: console $ pip install pytest-mock Changelog ========= Please consult the `changelog page`_. .. _changelog page: https://github.com/pytest-dev/pytest-mock/blob/master/CHANGELOG.rst Why bother with a plugin? ========================= There are a number of different ``patch`` usages in the standard ``mock`` API, but IMHO they don't scale very well when you have more than one or two patches to apply. It may lead to an excessive nesting of ``with`` statements, breaking the flow of the test: .. code-block:: python import mock def test_unix_fs(): with mock.patch('os.remove'): UnixFS.rm('file') os.remove.assert_called_once_with('file') with mock.patch('os.listdir'): assert UnixFS.ls('dir') == expected # ... with mock.patch('shutil.copy'): UnixFS.cp('src', 'dst') # ... One can use ``patch`` as a decorator to improve the flow of the test: .. code-block:: python @mock.patch('os.remove') @mock.patch('os.listdir') @mock.patch('shutil.copy') def test_unix_fs(mocked_copy, mocked_listdir, mocked_remove): UnixFS.rm('file') os.remove.assert_called_once_with('file') assert UnixFS.ls('dir') == expected # ... UnixFS.cp('src', 'dst') # ... But this poses a few disadvantages: - test functions must receive the mock objects as parameter, even if you don't plan to access them directly; also, order depends on the order of the decorated ``patch`` functions; - receiving the mocks as parameters doesn't mix nicely with pytest's approach of naming fixtures as parameters, or ``pytest.mark.parametrize``; - you can't easily undo the mocking during the test execution; An alternative is to use ``contextlib.ExitStack`` to stack the context managers in a single level of indentation to improve the flow of the test: .. code-block:: python import contextlib import mock def test_unix_fs(): with contextlib.ExitStack() as stack: stack.enter_context(mock.patch('os.remove')) UnixFS.rm('file') os.remove.assert_called_once_with('file') stack.enter_context(mock.patch('os.listdir')) assert UnixFS.ls('dir') == expected # ... stack.enter_context(mock.patch('shutil.copy')) UnixFS.cp('src', 'dst') # ... But this is arguably a little more complex than using ``pytest-mock``. Contributing ============ Contributions are welcome! After cloning the repository, create a virtual env and install ``pytest-mock`` in editable mode with ``dev`` extras: .. code-block:: console $ pip install --editable .[dev] $ pre-commit install Tests are run with ``tox``, you can run the baseline environments before submitting a PR: .. code-block:: console $ tox -e py38,linting Style checks and formatting are done automatically during commit courtesy of `pre-commit `_. License ======= Distributed under the terms of the `MIT`_ license. Security contact information ============================ To report a security vulnerability, please use the `Tidelift security contact `__. Tidelift will coordinate the fix and disclosure. .. _MIT: https://github.com/pytest-dev/pytest-mock/blob/master/LICENSE pytest-mock-3.6.1/mypy.ini0000644000175100001710000000047614045040650016303 0ustar runnerdocker00000000000000[mypy] disallow_any_generics = True disallow_incomplete_defs = True disallow_subclassing_any = True no_implicit_optional = True pretty = True show_error_codes = True strict_equality = True warn_redundant_casts = True warn_return_any = True warn_unreachable = True warn_unused_configs = True warn_unused_ignores = True pytest-mock-3.6.1/setup.cfg0000644000175100001710000000004614045040653016421 0ustar runnerdocker00000000000000[egg_info] tag_build = tag_date = 0 pytest-mock-3.6.1/setup.py0000644000175100001710000000273114045040650016312 0ustar runnerdocker00000000000000from io import open from setuptools import find_packages from setuptools import setup setup( name="pytest-mock", entry_points={"pytest11": ["pytest_mock = pytest_mock"]}, packages=find_packages(where="src"), package_dir={"": "src"}, platforms="any", package_data={ "pytest_mock": ["py.typed"], }, python_requires=">=3.6", install_requires=["pytest>=5.0"], use_scm_version={"write_to": "src/pytest_mock/_version.py"}, setup_requires=["setuptools_scm"], url="https://github.com/pytest-dev/pytest-mock/", license="MIT", author="Bruno Oliveira", author_email="nicoddemus@gmail.com", description="Thin-wrapper around the mock package for easier use with pytest", long_description=open("README.rst", encoding="utf-8").read(), keywords="pytest mock", extras_require={"dev": ["pre-commit", "tox", "pytest-asyncio"]}, classifiers=[ "Development Status :: 5 - Production/Stable", "Framework :: Pytest", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3 :: Only", "Topic :: Software Development :: Testing", ], ) pytest-mock-3.6.1/src/0000755000175100001710000000000014045040653015367 5ustar runnerdocker00000000000000pytest-mock-3.6.1/src/pytest_mock/0000755000175100001710000000000014045040653017730 5ustar runnerdocker00000000000000pytest-mock-3.6.1/src/pytest_mock/__init__.py0000644000175100001710000000127714045040650022045 0ustar runnerdocker00000000000000from pytest_mock.plugin import class_mocker from pytest_mock.plugin import mocker from pytest_mock.plugin import MockerFixture from pytest_mock.plugin import module_mocker from pytest_mock.plugin import package_mocker from pytest_mock.plugin import pytest_addoption from pytest_mock.plugin import pytest_configure from pytest_mock.plugin import PytestMockWarning from pytest_mock.plugin import session_mocker MockFixture = MockerFixture # backward-compatibility only (#204) __all__ = [ "MockerFixture", "MockFixture", "PytestMockWarning", "pytest_addoption", "pytest_configure", "session_mocker", "package_mocker", "module_mocker", "class_mocker", "mocker", ] pytest-mock-3.6.1/src/pytest_mock/_util.py0000644000175100001710000000164214045040650021416 0ustar runnerdocker00000000000000from typing import Union _mock_module = None def get_mock_module(config): """ Import and return the actual "mock" module. By default this is "unittest.mock", but the user can force to always use "mock" using the mock_use_standalone_module ini option. """ global _mock_module if _mock_module is None: use_standalone_module = parse_ini_boolean( config.getini("mock_use_standalone_module") ) if use_standalone_module: import mock _mock_module = mock else: import unittest.mock _mock_module = unittest.mock return _mock_module def parse_ini_boolean(value: Union[bool, str]) -> bool: if isinstance(value, bool): return value if value.lower() == "true": return True if value.lower() == "false": return False raise ValueError("unknown string for bool: %r" % value) pytest-mock-3.6.1/src/pytest_mock/_version.py0000644000175100001710000000021614045040653022125 0ustar runnerdocker00000000000000# coding: utf-8 # file generated by setuptools_scm # don't change, don't track in version control version = '3.6.1' version_tuple = (3, 6, 1) pytest-mock-3.6.1/src/pytest_mock/plugin.py0000644000175100001710000005061714045040650021606 0ustar runnerdocker00000000000000import asyncio import builtins import functools import inspect import sys import unittest.mock import warnings from typing import Any from typing import Callable from typing import cast from typing import Dict from typing import Generator from typing import Iterable from typing import List from typing import Mapping from typing import Optional from typing import overload from typing import Tuple from typing import Type from typing import TypeVar from typing import Union import pytest from ._util import get_mock_module from ._util import parse_ini_boolean _T = TypeVar("_T") class PytestMockWarning(UserWarning): """Base class for all warnings emitted by pytest-mock.""" class MockerFixture: """ Fixture that provides the same interface to functions in the mock module, ensuring that they are uninstalled at the end of each test. """ def __init__(self, config: Any) -> None: self._patches = [] # type: List[Any] self._mocks = [] # type: List[Any] self.mock_module = mock_module = get_mock_module(config) self.patch = self._Patcher( self._patches, self._mocks, mock_module ) # type: MockerFixture._Patcher # aliases for convenience self.Mock = mock_module.Mock self.MagicMock = mock_module.MagicMock self.NonCallableMock = mock_module.NonCallableMock self.PropertyMock = mock_module.PropertyMock if hasattr(mock_module, "AsyncMock"): self.AsyncMock = mock_module.AsyncMock self.call = mock_module.call self.ANY = mock_module.ANY self.DEFAULT = mock_module.DEFAULT self.create_autospec = mock_module.create_autospec self.sentinel = mock_module.sentinel self.mock_open = mock_module.mock_open if hasattr(mock_module, "seal"): self.seal = mock_module.seal def resetall( self, *, return_value: bool = False, side_effect: bool = False ) -> None: """ Call reset_mock() on all patchers started by this fixture. :param bool return_value: Reset the return_value of mocks. :param bool side_effect: Reset the side_effect of mocks. """ supports_reset_mock_with_args: Tuple[Type[Any], ...] if hasattr(self, "AsyncMock"): supports_reset_mock_with_args = (self.Mock, self.AsyncMock) else: supports_reset_mock_with_args = (self.Mock,) for m in self._mocks: # See issue #237. if isinstance(m, supports_reset_mock_with_args): m.reset_mock(return_value=return_value, side_effect=side_effect) else: m.reset_mock() def stopall(self) -> None: """ Stop all patchers started by this fixture. Can be safely called multiple times. """ for p in reversed(self._patches): p.stop() self._patches[:] = [] self._mocks[:] = [] def spy(self, obj: object, name: str) -> unittest.mock.MagicMock: """ Create a spy of method. It will run method normally, but it is now possible to use `mock` call features with it, like call count. :param obj: An object. :param name: A method in object. :return: Spy object. """ method = getattr(obj, name) if inspect.isclass(obj) and isinstance( inspect.getattr_static(obj, name), (classmethod, staticmethod) ): # Can't use autospec classmethod or staticmethod objects before 3.7 # see: https://bugs.python.org/issue23078 autospec = False else: autospec = inspect.ismethod(method) or inspect.isfunction(method) def wrapper(*args, **kwargs): spy_obj.spy_return = None spy_obj.spy_exception = None try: r = method(*args, **kwargs) except BaseException as e: spy_obj.spy_exception = e raise else: spy_obj.spy_return = r return r async def async_wrapper(*args, **kwargs): spy_obj.spy_return = None spy_obj.spy_exception = None try: r = await method(*args, **kwargs) except BaseException as e: spy_obj.spy_exception = e raise else: spy_obj.spy_return = r return r if asyncio.iscoroutinefunction(method): wrapped = functools.update_wrapper(async_wrapper, method) else: wrapped = functools.update_wrapper(wrapper, method) spy_obj = self.patch.object(obj, name, side_effect=wrapped, autospec=autospec) spy_obj.spy_return = None spy_obj.spy_exception = None return spy_obj def stub(self, name: Optional[str] = None) -> unittest.mock.MagicMock: """ Create a stub method. It accepts any arguments. Ideal to register to callbacks in tests. :param name: the constructed stub's name as used in repr :return: Stub object. """ return cast( unittest.mock.MagicMock, self.mock_module.MagicMock(spec=lambda *args, **kwargs: None, name=name), ) class _Patcher: """ Object to provide the same interface as mock.patch, mock.patch.object, etc. We need this indirection to keep the same API of the mock package. """ DEFAULT = object() def __init__(self, patches, mocks, mock_module): self._patches = patches self._mocks = mocks self.mock_module = mock_module def _start_patch( self, mock_func: Any, warn_on_mock_enter: bool, *args: Any, **kwargs: Any ) -> unittest.mock.MagicMock: """Patches something by calling the given function from the mock module, registering the patch to stop it later and returns the mock object resulting from the mock call. """ p = mock_func(*args, **kwargs) mocked = p.start() # type: unittest.mock.MagicMock self._patches.append(p) if hasattr(mocked, "reset_mock"): self._mocks.append(mocked) # check if `mocked` is actually a mock object, as depending on autospec or target # parameters `mocked` can be anything if hasattr(mocked, "__enter__") and warn_on_mock_enter: if sys.version_info >= (3, 8): depth = 5 else: depth = 4 mocked.__enter__.side_effect = lambda: warnings.warn( "Mocks returned by pytest-mock do not need to be used as context managers. " "The mocker fixture automatically undoes mocking at the end of a test. " "This warning can be ignored if it was triggered by mocking a context manager. " "https://github.com/pytest-dev/pytest-mock#note-about-usage-as-context-manager", PytestMockWarning, stacklevel=depth, ) return mocked def object( self, target: object, attribute: str, new: object = DEFAULT, spec: Optional[object] = None, create: bool = False, spec_set: Optional[object] = None, autospec: Optional[object] = None, new_callable: object = None, **kwargs: Any ) -> unittest.mock.MagicMock: """API to mock.patch.object""" if new is self.DEFAULT: new = self.mock_module.DEFAULT return self._start_patch( self.mock_module.patch.object, True, target, attribute, new=new, spec=spec, create=create, spec_set=spec_set, autospec=autospec, new_callable=new_callable, **kwargs ) def context_manager( self, target: builtins.object, attribute: str, new: builtins.object = DEFAULT, spec: Optional[builtins.object] = None, create: bool = False, spec_set: Optional[builtins.object] = None, autospec: Optional[builtins.object] = None, new_callable: builtins.object = None, **kwargs: Any ) -> unittest.mock.MagicMock: """This is equivalent to mock.patch.object except that the returned mock does not issue a warning when used as a context manager.""" if new is self.DEFAULT: new = self.mock_module.DEFAULT return self._start_patch( self.mock_module.patch.object, False, target, attribute, new=new, spec=spec, create=create, spec_set=spec_set, autospec=autospec, new_callable=new_callable, **kwargs ) def multiple( self, target: builtins.object, spec: Optional[builtins.object] = None, create: bool = False, spec_set: Optional[builtins.object] = None, autospec: Optional[builtins.object] = None, new_callable: Optional[builtins.object] = None, **kwargs: Any ) -> Dict[str, unittest.mock.MagicMock]: """API to mock.patch.multiple""" return self._start_patch( self.mock_module.patch.multiple, True, target, spec=spec, create=create, spec_set=spec_set, autospec=autospec, new_callable=new_callable, **kwargs ) def dict( self, in_dict: Union[Mapping[Any, Any], str], values: Union[Mapping[Any, Any], Iterable[Tuple[Any, Any]]] = (), clear: bool = False, **kwargs: Any ) -> Any: """API to mock.patch.dict""" return self._start_patch( self.mock_module.patch.dict, True, in_dict, values=values, clear=clear, **kwargs ) @overload def __call__( self, target: str, new: None = ..., spec: Optional[builtins.object] = ..., create: bool = ..., spec_set: Optional[builtins.object] = ..., autospec: Optional[builtins.object] = ..., new_callable: None = ..., **kwargs: Any ) -> unittest.mock.MagicMock: ... @overload def __call__( self, target: str, new: _T, spec: Optional[builtins.object] = ..., create: bool = ..., spec_set: Optional[builtins.object] = ..., autospec: Optional[builtins.object] = ..., new_callable: None = ..., **kwargs: Any ) -> _T: ... @overload def __call__( self, target: str, new: None, spec: Optional[builtins.object], create: bool, spec_set: Optional[builtins.object], autospec: Optional[builtins.object], new_callable: Callable[[], _T], **kwargs: Any ) -> _T: ... @overload def __call__( self, target: str, new: None = ..., spec: Optional[builtins.object] = ..., create: bool = ..., spec_set: Optional[builtins.object] = ..., autospec: Optional[builtins.object] = ..., *, new_callable: Callable[[], _T], **kwargs: Any ) -> _T: ... def __call__( self, target: str, new: builtins.object = DEFAULT, spec: Optional[builtins.object] = None, create: bool = False, spec_set: Optional[builtins.object] = None, autospec: Optional[builtins.object] = None, new_callable: Optional[Callable[[], Any]] = None, **kwargs: Any ) -> Any: """API to mock.patch""" if new is self.DEFAULT: new = self.mock_module.DEFAULT return self._start_patch( self.mock_module.patch, True, target, new=new, spec=spec, create=create, spec_set=spec_set, autospec=autospec, new_callable=new_callable, **kwargs ) def _mocker(pytestconfig: Any) -> Generator[MockerFixture, None, None]: """ Return an object that has the same interface to the `mock` module, but takes care of automatically undoing all patches after each test method. """ result = MockerFixture(pytestconfig) yield result result.stopall() mocker = pytest.fixture()(_mocker) # default scope is function class_mocker = pytest.fixture(scope="class")(_mocker) module_mocker = pytest.fixture(scope="module")(_mocker) package_mocker = pytest.fixture(scope="package")(_mocker) session_mocker = pytest.fixture(scope="session")(_mocker) _mock_module_patches = [] # type: List[Any] _mock_module_originals = {} # type: Dict[str, Any] def assert_wrapper( __wrapped_mock_method__: Callable[..., Any], *args: Any, **kwargs: Any ) -> None: __tracebackhide__ = True try: __wrapped_mock_method__(*args, **kwargs) return except AssertionError as e: if getattr(e, "_mock_introspection_applied", 0): msg = str(e) else: __mock_self = args[0] msg = str(e) if __mock_self.call_args is not None: actual_args, actual_kwargs = __mock_self.call_args introspection = "" try: assert actual_args == args[1:] except AssertionError as e_args: introspection += "\nArgs:\n" + str(e_args) try: assert actual_kwargs == kwargs except AssertionError as e_kwargs: introspection += "\nKwargs:\n" + str(e_kwargs) if introspection: msg += "\n\npytest introspection follows:\n" + introspection e = AssertionError(msg) e._mock_introspection_applied = True # type:ignore[attr-defined] raise e def wrap_assert_not_called(*args: Any, **kwargs: Any) -> None: __tracebackhide__ = True assert_wrapper(_mock_module_originals["assert_not_called"], *args, **kwargs) def wrap_assert_called_with(*args: Any, **kwargs: Any) -> None: __tracebackhide__ = True assert_wrapper(_mock_module_originals["assert_called_with"], *args, **kwargs) def wrap_assert_called_once(*args: Any, **kwargs: Any) -> None: __tracebackhide__ = True assert_wrapper(_mock_module_originals["assert_called_once"], *args, **kwargs) def wrap_assert_called_once_with(*args: Any, **kwargs: Any) -> None: __tracebackhide__ = True assert_wrapper(_mock_module_originals["assert_called_once_with"], *args, **kwargs) def wrap_assert_has_calls(*args: Any, **kwargs: Any) -> None: __tracebackhide__ = True assert_wrapper(_mock_module_originals["assert_has_calls"], *args, **kwargs) def wrap_assert_any_call(*args: Any, **kwargs: Any) -> None: __tracebackhide__ = True assert_wrapper(_mock_module_originals["assert_any_call"], *args, **kwargs) def wrap_assert_called(*args: Any, **kwargs: Any) -> None: __tracebackhide__ = True assert_wrapper(_mock_module_originals["assert_called"], *args, **kwargs) def wrap_assert_not_awaited(*args: Any, **kwargs: Any) -> None: __tracebackhide__ = True assert_wrapper(_mock_module_originals["assert_not_awaited"], *args, **kwargs) def wrap_assert_awaited_with(*args: Any, **kwargs: Any) -> None: __tracebackhide__ = True assert_wrapper(_mock_module_originals["assert_awaited_with"], *args, **kwargs) def wrap_assert_awaited_once(*args: Any, **kwargs: Any) -> None: __tracebackhide__ = True assert_wrapper(_mock_module_originals["assert_awaited_once"], *args, **kwargs) def wrap_assert_awaited_once_with(*args: Any, **kwargs: Any) -> None: __tracebackhide__ = True assert_wrapper(_mock_module_originals["assert_awaited_once_with"], *args, **kwargs) def wrap_assert_has_awaits(*args: Any, **kwargs: Any) -> None: __tracebackhide__ = True assert_wrapper(_mock_module_originals["assert_has_awaits"], *args, **kwargs) def wrap_assert_any_await(*args: Any, **kwargs: Any) -> None: __tracebackhide__ = True assert_wrapper(_mock_module_originals["assert_any_await"], *args, **kwargs) def wrap_assert_awaited(*args: Any, **kwargs: Any) -> None: __tracebackhide__ = True assert_wrapper(_mock_module_originals["assert_awaited"], *args, **kwargs) def wrap_assert_methods(config: Any) -> None: """ Wrap assert methods of mock module so we can hide their traceback and add introspection information to specified argument asserts. """ # Make sure we only do this once if _mock_module_originals: return mock_module = get_mock_module(config) wrappers = { "assert_called": wrap_assert_called, "assert_called_once": wrap_assert_called_once, "assert_called_with": wrap_assert_called_with, "assert_called_once_with": wrap_assert_called_once_with, "assert_any_call": wrap_assert_any_call, "assert_has_calls": wrap_assert_has_calls, "assert_not_called": wrap_assert_not_called, } for method, wrapper in wrappers.items(): try: original = getattr(mock_module.NonCallableMock, method) except AttributeError: # pragma: no cover continue _mock_module_originals[method] = original patcher = mock_module.patch.object(mock_module.NonCallableMock, method, wrapper) patcher.start() _mock_module_patches.append(patcher) if hasattr(mock_module, "AsyncMock"): async_wrappers = { "assert_awaited": wrap_assert_awaited, "assert_awaited_once": wrap_assert_awaited_once, "assert_awaited_with": wrap_assert_awaited_with, "assert_awaited_once_with": wrap_assert_awaited_once_with, "assert_any_await": wrap_assert_any_await, "assert_has_awaits": wrap_assert_has_awaits, "assert_not_awaited": wrap_assert_not_awaited, } for method, wrapper in async_wrappers.items(): try: original = getattr(mock_module.AsyncMock, method) except AttributeError: # pragma: no cover continue _mock_module_originals[method] = original patcher = mock_module.patch.object(mock_module.AsyncMock, method, wrapper) patcher.start() _mock_module_patches.append(patcher) config.add_cleanup(unwrap_assert_methods) def unwrap_assert_methods() -> None: for patcher in _mock_module_patches: try: patcher.stop() except RuntimeError as e: # a patcher might have been stopped by user code (#137) # so we need to catch this error here and ignore it; # unfortunately there's no public API to check if a patch # has been started, so catching the error it is if str(e) == "stop called on unstarted patcher": pass else: raise _mock_module_patches[:] = [] _mock_module_originals.clear() def pytest_addoption(parser: Any) -> None: parser.addini( "mock_traceback_monkeypatch", "Monkeypatch the mock library to improve reporting of the " "assert_called_... methods", default=True, ) parser.addini( "mock_use_standalone_module", 'Use standalone "mock" (from PyPI) instead of builtin "unittest.mock" ' "on Python 3", default=False, ) def pytest_configure(config: Any) -> None: tb = config.getoption("--tb", default="auto") if ( parse_ini_boolean(config.getini("mock_traceback_monkeypatch")) and tb != "native" ): wrap_assert_methods(config) pytest-mock-3.6.1/src/pytest_mock/py.typed0000644000175100001710000000000014045040650021412 0ustar runnerdocker00000000000000pytest-mock-3.6.1/src/pytest_mock.egg-info/0000755000175100001710000000000014045040653021422 5ustar runnerdocker00000000000000pytest-mock-3.6.1/src/pytest_mock.egg-info/PKG-INFO0000644000175100001710000004245414045040653022530 0ustar runnerdocker00000000000000Metadata-Version: 2.1 Name: pytest-mock Version: 3.6.1 Summary: Thin-wrapper around the mock package for easier use with pytest Home-page: https://github.com/pytest-dev/pytest-mock/ Author: Bruno Oliveira Author-email: nicoddemus@gmail.com License: MIT Description: =========== pytest-mock =========== This plugin provides a ``mocker`` fixture which is a thin-wrapper around the patching API provided by the `mock package `_: .. code-block:: python import os class UnixFS: @staticmethod def rm(filename): os.remove(filename) def test_unix_fs(mocker): mocker.patch('os.remove') UnixFS.rm('file') os.remove.assert_called_once_with('file') Besides undoing the mocking automatically after the end of the test, it also provides other nice utilities such as ``spy`` and ``stub``, and uses pytest introspection when comparing calls. |python| |version| |anaconda| |ci| |coverage| |black| |pre-commit| .. |version| image:: http://img.shields.io/pypi/v/pytest-mock.svg :target: https://pypi.python.org/pypi/pytest-mock .. |anaconda| image:: https://img.shields.io/conda/vn/conda-forge/pytest-mock.svg :target: https://anaconda.org/conda-forge/pytest-mock .. |ci| image:: https://github.com/pytest-dev/pytest-mock/workflows/build/badge.svg :target: https://github.com/pytest-dev/pytest-mock/actions .. |coverage| image:: https://coveralls.io/repos/github/pytest-dev/pytest-mock/badge.svg?branch=master :target: https://coveralls.io/github/pytest-dev/pytest-mock?branch=master .. |python| image:: https://img.shields.io/pypi/pyversions/pytest-mock.svg :target: https://pypi.python.org/pypi/pytest-mock/ .. |black| image:: https://img.shields.io/badge/code%20style-black-000000.svg :target: https://github.com/ambv/black .. |pre-commit| image:: https://results.pre-commit.ci/badge/github/pytest-dev/pytest-mock/master.svg :target: https://results.pre-commit.ci/latest/github/pytest-dev/pytest-mock/master `Professionally supported pytest-mock is now available `_ Usage ===== The ``mocker`` fixture has the same API as `mock.patch `_, supporting the same arguments: .. code-block:: python def test_foo(mocker): # all valid calls mocker.patch('os.remove') mocker.patch.object(os, 'listdir', autospec=True) mocked_isfile = mocker.patch('os.path.isfile') The supported methods are: * `mocker.patch `_ * `mocker.patch.object `_ * `mocker.patch.multiple `_ * `mocker.patch.dict `_ * `mocker.stopall `_ * ``mocker.resetall()``: calls `reset_mock() `_ in all mocked objects up to this point. Also, as a convenience, these names from the ``mock`` module are accessible directly from ``mocker``: * `Mock `_ * `MagicMock `_ * `PropertyMock `_ * `ANY `_ * `DEFAULT `_ *(Version 1.4)* * `call `_ *(Version 1.1)* * `sentinel `_ *(Version 1.2)* * `mock_open `_ * `seal `_ *(Version 3.4)* It is also possible to use mocking functionality from fixtures of other scopes using the appropriate mock fixture: * ``class_mocker`` * ``module_mocker`` * ``package_mocker`` * ``session_mocker`` Type Annotations ---------------- *New in version 3.3.0.* ``pytest-mock`` is fully type annotated, letting users use static type checkers to test their code. The ``mocker`` fixture returns ``pytest_mock.MockerFixture`` which can be used to annotate test functions: .. code-block:: python from pytest_mock import MockerFixture def test_foo(mocker: MockerFixture) -> None: ... The type annotations have been checked with ``mypy``, which is the only type checker supported at the moment; other type-checkers might work but are not currently tested. Spy --- The ``mocker.spy`` object acts exactly like the original method in all cases, except the spy also tracks function/method calls, return values and exceptions raised. .. code-block:: python def test_spy_method(mocker): class Foo(object): def bar(self, v): return v * 2 foo = Foo() spy = mocker.spy(foo, 'bar') assert foo.bar(21) == 42 spy.assert_called_once_with(21) assert spy.spy_return == 42 def test_spy_function(mocker): # mymodule declares `myfunction` which just returns 42 import mymodule spy = mocker.spy(mymodule, "myfunction") assert mymodule.myfunction() == 42 assert spy.call_count == 1 assert spy.spy_return == 42 The object returned by ``mocker.spy`` is a ``MagicMock`` object, so all standard checking functions are available (like ``assert_called_once_with`` or ``call_count`` in the examples above). In addition, spy objects contain two extra attributes: * ``spy_return``: contains the returned value of the spied function. * ``spy_exception``: contain the last exception value raised by the spied function/method when it was last called, or ``None`` if no exception was raised. Besides functions and normal methods, ``mocker.spy`` also works for class and static methods. As of version 3.0.0, ``mocker.spy`` also works with ``async def`` functions. .. note:: In versions earlier than ``2.0``, the attributes were called ``return_value`` and ``side_effect`` respectively, but due to incompatibilities with ``unittest.mock`` they had to be renamed (see `#175`_ for details). .. _#175: https://github.com/pytest-dev/pytest-mock/issues/175 Stub ---- The stub is a mock object that accepts any arguments and is useful to test callbacks. It may receive an optional name that is shown in its ``repr``, useful for debugging. .. code-block:: python def test_stub(mocker): def foo(on_something): on_something('foo', 'bar') stub = mocker.stub(name='on_something_stub') foo(stub) stub.assert_called_once_with('foo', 'bar') Improved reporting of mock call assertion errors ------------------------------------------------ This plugin monkeypatches the mock library to improve pytest output for failures of mock call assertions like ``Mock.assert_called_with()`` by hiding internal traceback entries from the ``mock`` module. It also adds introspection information on differing call arguments when calling the helper methods. This features catches `AssertionError` raised in the method, and uses pytest's own `advanced assertions`_ to return a better diff:: mocker = def test(mocker): m = mocker.Mock() m('fo') > m.assert_called_once_with('', bar=4) E AssertionError: Expected call: mock('', bar=4) E Actual call: mock('fo') E E pytest introspection follows: E E Args: E assert ('fo',) == ('',) E At index 0 diff: 'fo' != '' E Use -v to get the full diff E Kwargs: E assert {} == {'bar': 4} E Right contains more items: E {'bar': 4} E Use -v to get the full diff test_foo.py:6: AssertionError ========================== 1 failed in 0.03 seconds =========================== This is useful when asserting mock calls with many/nested arguments and trying to quickly see the difference. This feature is probably safe, but if you encounter any problems it can be disabled in your ``pytest.ini`` file: .. code-block:: ini [pytest] mock_traceback_monkeypatch = false Note that this feature is automatically disabled with the ``--tb=native`` option. The underlying mechanism used to suppress traceback entries from ``mock`` module does not work with that option anyway plus it generates confusing messages on Python 3.5 due to exception chaining .. _advanced assertions: http://docs.pytest.org/en/stable/assert.html Use standalone "mock" package ----------------------------- *New in version 1.4.0.* Python 3 users might want to use a newest version of the ``mock`` package as published on PyPI than the one that comes with the Python distribution. .. code-block:: ini [pytest] mock_use_standalone_module = true This will force the plugin to import ``mock`` instead of the ``unittest.mock`` module bundled with Python 3.4+. Note that this option is only used in Python 3+, as Python 2 users only have the option to use the ``mock`` package from PyPI anyway. Note about usage as context manager ----------------------------------- Although mocker's API is intentionally the same as ``mock.patch``'s, its use as context manager and function decorator is **not** supported through the fixture: .. code-block:: python def test_context_manager(mocker): a = A() with mocker.patch.object(a, 'doIt', return_value=True, autospec=True): # DO NOT DO THIS assert a.doIt() == True The purpose of this plugin is to make the use of context managers and function decorators for mocking unnecessary, so it will emit a warning when used as such. If you really intend to mock a context manager, ``mocker.patch.context_manager`` exists which won't issue the above warning. Install ======= Install using `pip `_: .. code-block:: console $ pip install pytest-mock Changelog ========= Please consult the `changelog page`_. .. _changelog page: https://github.com/pytest-dev/pytest-mock/blob/master/CHANGELOG.rst Why bother with a plugin? ========================= There are a number of different ``patch`` usages in the standard ``mock`` API, but IMHO they don't scale very well when you have more than one or two patches to apply. It may lead to an excessive nesting of ``with`` statements, breaking the flow of the test: .. code-block:: python import mock def test_unix_fs(): with mock.patch('os.remove'): UnixFS.rm('file') os.remove.assert_called_once_with('file') with mock.patch('os.listdir'): assert UnixFS.ls('dir') == expected # ... with mock.patch('shutil.copy'): UnixFS.cp('src', 'dst') # ... One can use ``patch`` as a decorator to improve the flow of the test: .. code-block:: python @mock.patch('os.remove') @mock.patch('os.listdir') @mock.patch('shutil.copy') def test_unix_fs(mocked_copy, mocked_listdir, mocked_remove): UnixFS.rm('file') os.remove.assert_called_once_with('file') assert UnixFS.ls('dir') == expected # ... UnixFS.cp('src', 'dst') # ... But this poses a few disadvantages: - test functions must receive the mock objects as parameter, even if you don't plan to access them directly; also, order depends on the order of the decorated ``patch`` functions; - receiving the mocks as parameters doesn't mix nicely with pytest's approach of naming fixtures as parameters, or ``pytest.mark.parametrize``; - you can't easily undo the mocking during the test execution; An alternative is to use ``contextlib.ExitStack`` to stack the context managers in a single level of indentation to improve the flow of the test: .. code-block:: python import contextlib import mock def test_unix_fs(): with contextlib.ExitStack() as stack: stack.enter_context(mock.patch('os.remove')) UnixFS.rm('file') os.remove.assert_called_once_with('file') stack.enter_context(mock.patch('os.listdir')) assert UnixFS.ls('dir') == expected # ... stack.enter_context(mock.patch('shutil.copy')) UnixFS.cp('src', 'dst') # ... But this is arguably a little more complex than using ``pytest-mock``. Contributing ============ Contributions are welcome! After cloning the repository, create a virtual env and install ``pytest-mock`` in editable mode with ``dev`` extras: .. code-block:: console $ pip install --editable .[dev] $ pre-commit install Tests are run with ``tox``, you can run the baseline environments before submitting a PR: .. code-block:: console $ tox -e py38,linting Style checks and formatting are done automatically during commit courtesy of `pre-commit `_. License ======= Distributed under the terms of the `MIT`_ license. Security contact information ============================ To report a security vulnerability, please use the `Tidelift security contact `__. Tidelift will coordinate the fix and disclosure. .. _MIT: https://github.com/pytest-dev/pytest-mock/blob/master/LICENSE Keywords: pytest mock Platform: any Classifier: Development Status :: 5 - Production/Stable Classifier: Framework :: Pytest Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3 :: Only Classifier: Topic :: Software Development :: Testing Requires-Python: >=3.6 Provides-Extra: dev pytest-mock-3.6.1/src/pytest_mock.egg-info/SOURCES.txt0000644000175100001710000000104714045040653023310 0ustar runnerdocker00000000000000.gitignore .pre-commit-config.yaml CHANGELOG.rst HOWTORELEASE.rst LICENSE README.rst mypy.ini setup.py tox.ini .github/FUNDING.yml .github/workflows/main.yml src/pytest_mock/__init__.py src/pytest_mock/_util.py src/pytest_mock/_version.py src/pytest_mock/plugin.py src/pytest_mock/py.typed src/pytest_mock.egg-info/PKG-INFO src/pytest_mock.egg-info/SOURCES.txt src/pytest_mock.egg-info/dependency_links.txt src/pytest_mock.egg-info/entry_points.txt src/pytest_mock.egg-info/requires.txt src/pytest_mock.egg-info/top_level.txt tests/test_pytest_mock.pypytest-mock-3.6.1/src/pytest_mock.egg-info/dependency_links.txt0000644000175100001710000000000114045040653025470 0ustar runnerdocker00000000000000 pytest-mock-3.6.1/src/pytest_mock.egg-info/entry_points.txt0000644000175100001710000000004614045040653024720 0ustar runnerdocker00000000000000[pytest11] pytest_mock = pytest_mock pytest-mock-3.6.1/src/pytest_mock.egg-info/requires.txt0000644000175100001710000000006114045040653024017 0ustar runnerdocker00000000000000pytest>=5.0 [dev] pre-commit tox pytest-asyncio pytest-mock-3.6.1/src/pytest_mock.egg-info/top_level.txt0000644000175100001710000000001414045040653024147 0ustar runnerdocker00000000000000pytest_mock pytest-mock-3.6.1/tests/0000755000175100001710000000000014045040653015742 5ustar runnerdocker00000000000000pytest-mock-3.6.1/tests/test_pytest_mock.py0000644000175100001710000007301514045040650021717 0ustar runnerdocker00000000000000import os import platform import re import sys from contextlib import contextmanager from typing import Any from typing import Callable from typing import Generator from typing import Tuple from typing import Type from unittest.mock import MagicMock import pytest from pytest_mock import MockerFixture from pytest_mock import PytestMockWarning pytest_plugins = "pytester" # could not make some of the tests work on PyPy, patches are welcome! skip_pypy = pytest.mark.skipif( platform.python_implementation() == "PyPy", reason="could not make it work on pypy" ) # Python 3.8 changed the output formatting (bpo-35500), which has been ported to mock 3.0 NEW_FORMATTING = sys.version_info >= (3, 8) @pytest.fixture def needs_assert_rewrite(pytestconfig): """ Fixture which skips requesting test if assertion rewrite is disabled (#102) Making this a fixture to avoid acessing pytest's config in the global context. """ option = pytestconfig.getoption("assertmode") if option != "rewrite": pytest.skip( "this test needs assertion rewrite to work but current option " 'is "{}"'.format(option) ) class UnixFS: """ Wrapper to os functions to simulate a Unix file system, used for testing the mock fixture. """ @classmethod def rm(cls, filename): os.remove(filename) @classmethod def ls(cls, path): return os.listdir(path) @pytest.fixture def check_unix_fs_mocked( tmpdir: Any, mocker: MockerFixture ) -> Callable[[Any, Any], None]: """ performs a standard test in a UnixFS, assuming that both `os.remove` and `os.listdir` have been mocked previously. """ def check(mocked_rm, mocked_ls): assert mocked_rm is os.remove assert mocked_ls is os.listdir file_name = tmpdir / "foo.txt" file_name.ensure() UnixFS.rm(str(file_name)) mocked_rm.assert_called_once_with(str(file_name)) assert os.path.isfile(str(file_name)) mocked_ls.return_value = ["bar.txt"] assert UnixFS.ls(str(tmpdir)) == ["bar.txt"] mocked_ls.assert_called_once_with(str(tmpdir)) mocker.stopall() assert UnixFS.ls(str(tmpdir)) == ["foo.txt"] UnixFS.rm(str(file_name)) assert not os.path.isfile(str(file_name)) return check def mock_using_patch_object(mocker: MockerFixture) -> Tuple[MagicMock, MagicMock]: return mocker.patch.object(os, "remove"), mocker.patch.object(os, "listdir") def mock_using_patch(mocker: MockerFixture) -> Tuple[MagicMock, MagicMock]: return mocker.patch("os.remove"), mocker.patch("os.listdir") def mock_using_patch_multiple(mocker: MockerFixture) -> Tuple[MagicMock, MagicMock]: r = mocker.patch.multiple("os", remove=mocker.DEFAULT, listdir=mocker.DEFAULT) return r["remove"], r["listdir"] @pytest.mark.parametrize( "mock_fs", [mock_using_patch_object, mock_using_patch, mock_using_patch_multiple] ) def test_mock_patches( mock_fs: Any, mocker: MockerFixture, check_unix_fs_mocked: Callable[[Any, Any], None], ) -> None: """ Installs mocks into `os` functions and performs a standard testing of mock functionality. We parametrize different mock methods to ensure all (intended, at least) mock API is covered. """ # mock it twice on purpose to ensure we unmock it correctly later mock_fs(mocker) mocked_rm, mocked_ls = mock_fs(mocker) check_unix_fs_mocked(mocked_rm, mocked_ls) mocker.resetall() mocker.stopall() def test_mock_patch_dict(mocker: MockerFixture) -> None: """ Testing :param mock: """ x = {"original": 1} mocker.patch.dict(x, values=[("new", 10)], clear=True) assert x == {"new": 10} mocker.stopall() assert x == {"original": 1} def test_mock_patch_dict_resetall(mocker: MockerFixture) -> None: """ We can call resetall after patching a dict. :param mock: """ x = {"original": 1} mocker.patch.dict(x, values=[("new", 10)], clear=True) assert x == {"new": 10} mocker.resetall() assert x == {"new": 10} @pytest.mark.parametrize( "name", [ "ANY", "call", "create_autospec", "MagicMock", "Mock", "mock_open", "NonCallableMock", "PropertyMock", "sentinel", pytest.param( "seal", marks=pytest.mark.skipif( sys.version_info < (3, 7), reason="seal is present on 3.7 and above" ), ), ], ) def test_mocker_aliases(name: str, pytestconfig: Any) -> None: from pytest_mock._util import get_mock_module mock_module = get_mock_module(pytestconfig) mocker = MockerFixture(pytestconfig) assert getattr(mocker, name) is getattr(mock_module, name) def test_mocker_resetall(mocker: MockerFixture) -> None: listdir = mocker.patch("os.listdir", return_value="foo") open = mocker.patch("os.open", side_effect=["bar", "baz"]) assert listdir("/tmp") == "foo" assert open("/tmp/foo.txt") == "bar" listdir.assert_called_once_with("/tmp") open.assert_called_once_with("/tmp/foo.txt") mocker.resetall() assert not listdir.called assert not open.called assert listdir.return_value == "foo" assert list(open.side_effect) == ["baz"] mocker.resetall(return_value=True, side_effect=True) assert isinstance(listdir.return_value, mocker.Mock) assert open.side_effect is None class TestMockerStub: def test_call(self, mocker: MockerFixture) -> None: stub = mocker.stub() stub("foo", "bar") stub.assert_called_once_with("foo", "bar") def test_repr_with_no_name(self, mocker: MockerFixture) -> None: stub = mocker.stub() assert "name" not in repr(stub) def test_repr_with_name(self, mocker: MockerFixture) -> None: test_name = "funny walk" stub = mocker.stub(name=test_name) assert "name={!r}".format(test_name) in repr(stub) def __test_failure_message(self, mocker: MockerFixture, **kwargs: Any) -> None: expected_name = kwargs.get("name") or "mock" if NEW_FORMATTING: msg = "expected call not found.\nExpected: {0}()\nActual: not called." else: msg = "Expected call: {0}()\nNot called" expected_message = msg.format(expected_name) stub = mocker.stub(**kwargs) with pytest.raises(AssertionError) as exc_info: stub.assert_called_with() assert str(exc_info.value) == expected_message def test_failure_message_with_no_name(self, mocker: MagicMock) -> None: self.__test_failure_message(mocker) @pytest.mark.parametrize("name", (None, "", "f", "The Castle of aaarrrrggh")) def test_failure_message_with_name(self, mocker: MagicMock, name: str) -> None: self.__test_failure_message(mocker, name=name) def test_instance_method_spy(mocker: MockerFixture) -> None: class Foo: def bar(self, arg): return arg * 2 foo = Foo() other = Foo() spy = mocker.spy(foo, "bar") assert foo.bar(arg=10) == 20 assert other.bar(arg=10) == 20 foo.bar.assert_called_once_with(arg=10) # type:ignore[attr-defined] assert foo.bar.spy_return == 20 # type:ignore[attr-defined] spy.assert_called_once_with(arg=10) assert spy.spy_return == 20 # Ref: https://docs.python.org/3/library/exceptions.html#exception-hierarchy @pytest.mark.parametrize( "exc_cls", ( BaseException, Exception, GeneratorExit, # BaseException KeyboardInterrupt, # BaseException RuntimeError, # regular Exception SystemExit, # BaseException ), ) def test_instance_method_spy_exception( exc_cls: Type[BaseException], mocker: MockerFixture, ) -> None: class Foo: def bar(self, arg): raise exc_cls("Error with {}".format(arg)) foo = Foo() spy = mocker.spy(foo, "bar") expected_calls = [] for i, v in enumerate([10, 20]): with pytest.raises(exc_cls, match="Error with {}".format(v)): foo.bar(arg=v) expected_calls.append(mocker.call(arg=v)) assert foo.bar.call_args_list == expected_calls # type:ignore[attr-defined] assert str(spy.spy_exception) == "Error with {}".format(v) def test_instance_method_spy_autospec_true(mocker: MockerFixture) -> None: class Foo: def bar(self, arg): return arg * 2 foo = Foo() spy = mocker.spy(foo, "bar") with pytest.raises( AttributeError, match="'function' object has no attribute 'fake_assert_method'" ): spy.fake_assert_method(arg=5) def test_spy_reset(mocker: MockerFixture) -> None: class Foo(object): def bar(self, x): if x == 0: raise ValueError("invalid x") return x * 3 spy = mocker.spy(Foo, "bar") assert spy.spy_return is None assert spy.spy_exception is None Foo().bar(10) assert spy.spy_return == 30 assert spy.spy_exception is None # Testing spy can still be reset (#237). mocker.resetall() with pytest.raises(ValueError): Foo().bar(0) assert spy.spy_return is None assert str(spy.spy_exception) == "invalid x" Foo().bar(15) assert spy.spy_return == 45 assert spy.spy_exception is None @skip_pypy def test_instance_method_by_class_spy(mocker: MockerFixture) -> None: class Foo: def bar(self, arg): return arg * 2 spy = mocker.spy(Foo, "bar") foo = Foo() other = Foo() assert foo.bar(arg=10) == 20 assert other.bar(arg=10) == 20 calls = [mocker.call(foo, arg=10), mocker.call(other, arg=10)] assert spy.call_args_list == calls @skip_pypy def test_instance_method_by_subclass_spy(mocker: MockerFixture) -> None: class Base: def bar(self, arg): return arg * 2 class Foo(Base): pass spy = mocker.spy(Foo, "bar") foo = Foo() other = Foo() assert foo.bar(arg=10) == 20 assert other.bar(arg=10) == 20 calls = [mocker.call(foo, arg=10), mocker.call(other, arg=10)] assert spy.call_args_list == calls assert spy.spy_return == 20 @skip_pypy def test_class_method_spy(mocker: MockerFixture) -> None: class Foo: @classmethod def bar(cls, arg): return arg * 2 spy = mocker.spy(Foo, "bar") assert Foo.bar(arg=10) == 20 Foo.bar.assert_called_once_with(arg=10) # type:ignore[attr-defined] assert Foo.bar.spy_return == 20 # type:ignore[attr-defined] spy.assert_called_once_with(arg=10) assert spy.spy_return == 20 @skip_pypy def test_class_method_spy_autospec_false(mocker: MockerFixture) -> None: class Foo: @classmethod def bar(cls, arg): return arg * 2 spy = mocker.spy(Foo, "bar") spy.fake_assert_method() @skip_pypy def test_class_method_subclass_spy(mocker: MockerFixture) -> None: class Base: @classmethod def bar(self, arg): return arg * 2 class Foo(Base): pass spy = mocker.spy(Foo, "bar") assert Foo.bar(arg=10) == 20 Foo.bar.assert_called_once_with(arg=10) # type:ignore[attr-defined] assert Foo.bar.spy_return == 20 # type:ignore[attr-defined] spy.assert_called_once_with(arg=10) assert spy.spy_return == 20 @skip_pypy def test_class_method_with_metaclass_spy(mocker: MockerFixture) -> None: class MetaFoo(type): pass class Foo: __metaclass__ = MetaFoo @classmethod def bar(cls, arg): return arg * 2 spy = mocker.spy(Foo, "bar") assert Foo.bar(arg=10) == 20 Foo.bar.assert_called_once_with(arg=10) # type:ignore[attr-defined] assert Foo.bar.spy_return == 20 # type:ignore[attr-defined] spy.assert_called_once_with(arg=10) assert spy.spy_return == 20 @skip_pypy def test_static_method_spy(mocker: MockerFixture) -> None: class Foo: @staticmethod def bar(arg): return arg * 2 spy = mocker.spy(Foo, "bar") assert Foo.bar(arg=10) == 20 Foo.bar.assert_called_once_with(arg=10) # type:ignore[attr-defined] assert Foo.bar.spy_return == 20 # type:ignore[attr-defined] spy.assert_called_once_with(arg=10) assert spy.spy_return == 20 @skip_pypy def test_static_method_subclass_spy(mocker: MockerFixture) -> None: class Base: @staticmethod def bar(arg): return arg * 2 class Foo(Base): pass spy = mocker.spy(Foo, "bar") assert Foo.bar(arg=10) == 20 Foo.bar.assert_called_once_with(arg=10) # type:ignore[attr-defined] assert Foo.bar.spy_return == 20 # type:ignore[attr-defined] spy.assert_called_once_with(arg=10) assert spy.spy_return == 20 def test_callable_like_spy(testdir: Any, mocker: MockerFixture) -> None: testdir.makepyfile( uut=""" class CallLike(object): def __call__(self, x): return x * 2 call_like = CallLike() """ ) testdir.syspathinsert() uut = __import__("uut") spy = mocker.spy(uut, "call_like") uut.call_like(10) spy.assert_called_once_with(10) assert spy.spy_return == 20 @pytest.mark.asyncio async def test_instance_async_method_spy(mocker: MockerFixture) -> None: class Foo: async def bar(self, arg): return arg * 2 foo = Foo() spy = mocker.spy(foo, "bar") result = await foo.bar(10) spy.assert_called_once_with(10) assert result == 20 @contextmanager def assert_traceback() -> Generator[None, None, None]: """ Assert that this file is at the top of the filtered traceback """ try: yield except AssertionError as e: assert e.__traceback__.tb_frame.f_code.co_filename == __file__ # type:ignore else: raise AssertionError("DID NOT RAISE") @contextmanager def assert_argument_introspection(left: Any, right: Any) -> Generator[None, None, None]: """ Assert detailed argument introspection is used """ try: yield except AssertionError as e: # this may be a bit too assuming, but seems nicer then hard-coding import _pytest.assertion.util as util # NOTE: we assert with either verbose or not, depending on how our own # test was run by examining sys.argv verbose = any(a.startswith("-v") for a in sys.argv) expected = "\n ".join(util._compare_eq_iterable(left, right, verbose)) assert expected in str(e) else: raise AssertionError("DID NOT RAISE") def test_assert_not_called_wrapper(mocker: MockerFixture) -> None: stub = mocker.stub() stub.assert_not_called() stub() with assert_traceback(): stub.assert_not_called() def test_assert_called_with_wrapper(mocker: MockerFixture) -> None: stub = mocker.stub() stub("foo") stub.assert_called_with("foo") with assert_traceback(): stub.assert_called_with("bar") def test_assert_called_once_with_wrapper(mocker: MockerFixture) -> None: stub = mocker.stub() stub("foo") stub.assert_called_once_with("foo") stub("foo") with assert_traceback(): stub.assert_called_once_with("foo") def test_assert_called_once_wrapper(mocker: MockerFixture) -> None: stub = mocker.stub() if not hasattr(stub, "assert_called_once"): pytest.skip("assert_called_once not available") stub("foo") stub.assert_called_once() stub("foo") with assert_traceback(): stub.assert_called_once() def test_assert_called_wrapper(mocker: MockerFixture) -> None: stub = mocker.stub() if not hasattr(stub, "assert_called"): pytest.skip("assert_called_once not available") with assert_traceback(): stub.assert_called() stub("foo") stub.assert_called() stub("foo") stub.assert_called() @pytest.mark.usefixtures("needs_assert_rewrite") def test_assert_called_args_with_introspection(mocker: MockerFixture) -> None: stub = mocker.stub() complex_args = ("a", 1, {"test"}) wrong_args = ("b", 2, {"jest"}) stub(*complex_args) stub.assert_called_with(*complex_args) stub.assert_called_once_with(*complex_args) with assert_argument_introspection(complex_args, wrong_args): stub.assert_called_with(*wrong_args) stub.assert_called_once_with(*wrong_args) @pytest.mark.usefixtures("needs_assert_rewrite") def test_assert_called_kwargs_with_introspection(mocker: MockerFixture) -> None: stub = mocker.stub() complex_kwargs = dict(foo={"bar": 1, "baz": "spam"}) wrong_kwargs = dict(foo={"goo": 1, "baz": "bran"}) stub(**complex_kwargs) stub.assert_called_with(**complex_kwargs) stub.assert_called_once_with(**complex_kwargs) with assert_argument_introspection(complex_kwargs, wrong_kwargs): stub.assert_called_with(**wrong_kwargs) stub.assert_called_once_with(**wrong_kwargs) def test_assert_any_call_wrapper(mocker: MockerFixture) -> None: stub = mocker.stub() stub("foo") stub("foo") stub.assert_any_call("foo") with assert_traceback(): stub.assert_any_call("bar") def test_assert_has_calls(mocker: MockerFixture) -> None: stub = mocker.stub() stub("foo") stub.assert_has_calls([mocker.call("foo")]) with assert_traceback(): stub.assert_has_calls([mocker.call("bar")]) def test_monkeypatch_ini(testdir: Any, mocker: MockerFixture) -> None: # Make sure the following function actually tests something stub = mocker.stub() assert stub.assert_called_with.__module__ != stub.__module__ testdir.makepyfile( """ import py.code def test_foo(mocker): stub = mocker.stub() assert stub.assert_called_with.__module__ == stub.__module__ """ ) testdir.makeini( """ [pytest] mock_traceback_monkeypatch = false """ ) result = testdir.runpytest_subprocess() assert result.ret == 0 def test_parse_ini_boolean() -> None: from pytest_mock._util import parse_ini_boolean assert parse_ini_boolean("True") is True assert parse_ini_boolean("false") is False with pytest.raises(ValueError): parse_ini_boolean("foo") def test_patched_method_parameter_name(mocker: MockerFixture) -> None: """Test that our internal code uses uncommon names when wrapping other "mock" methods to avoid conflicts with user code (#31). """ class Request: @classmethod def request(cls, method, args): pass m = mocker.patch.object(Request, "request") Request.request(method="get", args={"type": "application/json"}) m.assert_called_once_with(method="get", args={"type": "application/json"}) def test_monkeypatch_native(testdir: Any) -> None: """Automatically disable monkeypatching when --tb=native.""" testdir.makepyfile( """ def test_foo(mocker): stub = mocker.stub() stub(1, greet='hello') stub.assert_called_once_with(1, greet='hey') """ ) result = testdir.runpytest_subprocess("--tb=native") assert result.ret == 1 assert "During handling of the above exception" not in result.stdout.str() assert "Differing items:" not in result.stdout.str() traceback_lines = [ x for x in result.stdout.str().splitlines() if "Traceback (most recent call last)" in x ] assert ( len(traceback_lines) == 1 ) # make sure there are no duplicated tracebacks (#44) def test_monkeypatch_no_terminal(testdir: Any) -> None: """Don't crash without 'terminal' plugin.""" testdir.makepyfile( """ def test_foo(mocker): stub = mocker.stub() stub(1, greet='hello') stub.assert_called_once_with(1, greet='hey') """ ) result = testdir.runpytest_subprocess("-p", "no:terminal", "-s") assert result.ret == 1 assert result.stdout.lines == [] def test_standalone_mock(testdir: Any) -> None: """Check that the "mock_use_standalone" is being used.""" testdir.makepyfile( """ def test_foo(mocker): pass """ ) testdir.makeini( """ [pytest] mock_use_standalone_module = true """ ) result = testdir.runpytest_subprocess() assert result.ret == 3 result.stderr.fnmatch_lines(["*No module named 'mock'*"]) @pytest.mark.usefixtures("needs_assert_rewrite") def test_detailed_introspection(testdir: Any) -> None: """Check that the "mock_use_standalone" is being used.""" testdir.makepyfile( """ def test(mocker): m = mocker.Mock() m('fo') m.assert_called_once_with('', bar=4) """ ) result = testdir.runpytest("-s") if NEW_FORMATTING: expected_lines = [ "*AssertionError: expected call not found.", "*Expected: mock('', bar=4)", "*Actual: mock('fo')", ] else: expected_lines = [ "*AssertionError: Expected call: mock('', bar=4)*", "*Actual call: mock('fo')*", ] expected_lines += [ "*pytest introspection follows:*", "*Args:", "*assert ('fo',) == ('',)", "*At index 0 diff: 'fo' != ''*", "*Use -v to get the full diff*", "*Kwargs:*", "*assert {} == {'bar': 4}*", "*Right contains* more item*", "*{'bar': 4}*", "*Use -v to get the full diff*", ] result.stdout.fnmatch_lines(expected_lines) @pytest.mark.skipif( sys.version_info < (3, 8), reason="AsyncMock is present on 3.8 and above" ) @pytest.mark.usefixtures("needs_assert_rewrite") def test_detailed_introspection_async(testdir: Any) -> None: """Check that the "mock_use_standalone" is being used.""" testdir.makepyfile( """ import pytest @pytest.mark.asyncio async def test(mocker): m = mocker.AsyncMock() await m('fo') m.assert_awaited_once_with('', bar=4) """ ) result = testdir.runpytest("-s") expected_lines = [ "*AssertionError: expected await not found.", "*Expected: mock('', bar=4)", "*Actual: mock('fo')", "*pytest introspection follows:*", "*Args:", "*assert ('fo',) == ('',)", "*At index 0 diff: 'fo' != ''*", "*Use -v to get the full diff*", "*Kwargs:*", "*assert {} == {'bar': 4}*", "*Right contains* more item*", "*{'bar': 4}*", "*Use -v to get the full diff*", ] result.stdout.fnmatch_lines(expected_lines) def test_missing_introspection(testdir: Any) -> None: testdir.makepyfile( """ def test_foo(mocker): mock = mocker.Mock() mock('foo') mock('test') mock.assert_called_once_with('test') """ ) result = testdir.runpytest() assert "pytest introspection follows:" not in result.stdout.str() def test_assert_called_with_unicode_arguments(mocker: MockerFixture) -> None: """Test bug in assert_call_with called with non-ascii unicode string (#91)""" stub = mocker.stub() stub(b"l\xc3\xb6k".decode("UTF-8")) with pytest.raises(AssertionError): stub.assert_called_with("lak") def test_plain_stopall(testdir: Any) -> None: """patch.stopall() in a test should not cause an error during unconfigure (#137)""" testdir.makepyfile( """ import random def get_random_number(): return random.randint(0, 100) def test_get_random_number(mocker): patcher = mocker.mock_module.patch("random.randint", lambda x, y: 5) patcher.start() assert get_random_number() == 5 mocker.mock_module.patch.stopall() """ ) result = testdir.runpytest_subprocess() result.stdout.fnmatch_lines("* 1 passed in *") assert "RuntimeError" not in result.stderr.str() def test_warn_patch_object_context_manager(mocker: MockerFixture) -> None: class A: def doIt(self): return False a = A() expected_warning_msg = ( "Mocks returned by pytest-mock do not need to be used as context managers. " "The mocker fixture automatically undoes mocking at the end of a test. " "This warning can be ignored if it was triggered by mocking a context manager. " "https://github.com/pytest-dev/pytest-mock#note-about-usage-as-context-manager" ) with pytest.warns( PytestMockWarning, match=re.escape(expected_warning_msg) ) as warn_record: with mocker.patch.object(a, "doIt", return_value=True): assert a.doIt() is True assert warn_record[0].filename == __file__ def test_warn_patch_context_manager(mocker: MockerFixture) -> None: expected_warning_msg = ( "Mocks returned by pytest-mock do not need to be used as context managers. " "The mocker fixture automatically undoes mocking at the end of a test. " "This warning can be ignored if it was triggered by mocking a context manager. " "https://github.com/pytest-dev/pytest-mock#note-about-usage-as-context-manager" ) with pytest.warns( PytestMockWarning, match=re.escape(expected_warning_msg) ) as warn_record: with mocker.patch("json.loads"): pass assert warn_record[0].filename == __file__ def test_context_manager_patch_example(mocker: MockerFixture) -> None: """Our message about misusing mocker as a context manager should not affect mocking context managers (see #192)""" class dummy_module: class MyContext: def __enter__(self, *args, **kwargs): return 10 def __exit__(self, *args, **kwargs): pass def my_func(): with dummy_module.MyContext() as v: return v m = mocker.patch.object(dummy_module, "MyContext") assert isinstance(my_func(), mocker.MagicMock) def test_patch_context_manager_with_context_manager(mocker: MockerFixture) -> None: """Test that no warnings are issued when an object patched with patch.context_manager is used as a context manager (#221)""" class A: def doIt(self): return False a = A() with pytest.warns(None) as warn_record: with mocker.patch.context_manager(a, "doIt", return_value=True): assert a.doIt() is True assert len(warn_record) == 0 def test_abort_patch_context_manager_with_stale_pyc(testdir: Any) -> None: """Ensure we don't trigger an error in case the frame where mocker.patch is being used doesn't have a 'context' (#169)""" import compileall py_fn = testdir.makepyfile( c=""" class C: x = 1 def check(mocker): mocker.patch.object(C, "x", 2) assert C.x == 2 """ ) testdir.syspathinsert() testdir.makepyfile( """ from c import check def test_foo(mocker): check(mocker) """ ) result = testdir.runpytest() result.assert_outcomes(passed=1) assert compileall.compile_file(str(py_fn), legacy=True) pyc_fn = str(py_fn) + "c" assert os.path.isfile(pyc_fn) py_fn.remove() result = testdir.runpytest() result.assert_outcomes(passed=1) def test_used_with_class_scope(testdir: Any) -> None: testdir.makepyfile( """ import pytest import random import unittest def get_random_number(): return random.randint(0, 1) @pytest.fixture(autouse=True, scope="class") def randint_mock(class_mocker): return class_mocker.patch("random.randint", lambda x, y: 5) class TestGetRandomNumber(unittest.TestCase): def test_get_random_number(self): assert get_random_number() == 5 """ ) result = testdir.runpytest_subprocess() assert "AssertionError" not in result.stderr.str() result.stdout.fnmatch_lines("* 1 passed in *") def test_used_with_module_scope(testdir: Any) -> None: testdir.makepyfile( """ import pytest import random def get_random_number(): return random.randint(0, 1) @pytest.fixture(autouse=True, scope="module") def randint_mock(module_mocker): return module_mocker.patch("random.randint", lambda x, y: 5) def test_get_random_number(): assert get_random_number() == 5 """ ) result = testdir.runpytest_subprocess() assert "AssertionError" not in result.stderr.str() result.stdout.fnmatch_lines("* 1 passed in *") def test_used_with_package_scope(testdir: Any) -> None: """...""" testdir.makepyfile( """ import pytest import random def get_random_number(): return random.randint(0, 1) @pytest.fixture(autouse=True, scope="package") def randint_mock(package_mocker): return package_mocker.patch("random.randint", lambda x, y: 5) def test_get_random_number(): assert get_random_number() == 5 """ ) result = testdir.runpytest_subprocess() assert "AssertionError" not in result.stderr.str() result.stdout.fnmatch_lines("* 1 passed in *") def test_used_with_session_scope(testdir: Any) -> None: """...""" testdir.makepyfile( """ import pytest import random def get_random_number(): return random.randint(0, 1) @pytest.fixture(autouse=True, scope="session") def randint_mock(session_mocker): return session_mocker.patch("random.randint", lambda x, y: 5) def test_get_random_number(): assert get_random_number() == 5 """ ) result = testdir.runpytest_subprocess() assert "AssertionError" not in result.stderr.str() result.stdout.fnmatch_lines("* 1 passed in *") pytest-mock-3.6.1/tox.ini0000644000175100001710000000112014045040650016102 0ustar runnerdocker00000000000000[tox] minversion = 3.5.3 envlist = py{35,36,37,38,39}, linting, norewrite [testenv] passenv = USER USERNAME deps = coverage pytest-asyncio commands = coverage run --append --source={envsitepackagesdir}/pytest_mock -m pytest tests [testenv:norewrite] commands = pytest tests --assert=plain [testenv:linting] usedevelop = True extras = dev basepython = python3.6 commands = pre-commit run --all-files --show-diff-on-failure [testenv:mypy] skip_install = true deps = mypy==0.800 commands = mypy {posargs:src tests} [pytest] addopts = -r a [flake8] max-line-length = 88