New upstream version 1.10.4
This commit is contained in:
parent
cde0d28bf2
commit
e5f34a66ea
22
.pre-commit-config.yaml
Normal file
22
.pre-commit-config.yaml
Normal file
|
@ -0,0 +1,22 @@
|
|||
exclude: '^($|.*\.bin)'
|
||||
repos:
|
||||
- repo: https://github.com/ambv/black
|
||||
rev: 18.6b4
|
||||
hooks:
|
||||
- id: black
|
||||
args: [--safe, --quiet]
|
||||
language_version: python3.6
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v1.3.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]
|
||||
python_version: python3.6
|
26
.travis.yml
26
.travis.yml
|
@ -1,12 +1,9 @@
|
|||
language: python
|
||||
python:
|
||||
- "2.7"
|
||||
- "3.4"
|
||||
- "3.5"
|
||||
- "3.6"
|
||||
dist: xenial
|
||||
|
||||
install:
|
||||
- pip install tox-travis coveralls
|
||||
- pip install -U pip
|
||||
- pip install tox coveralls
|
||||
|
||||
script:
|
||||
- tox
|
||||
|
@ -14,8 +11,25 @@ script:
|
|||
after_success:
|
||||
- coveralls
|
||||
|
||||
stages:
|
||||
- test
|
||||
- name: deploy
|
||||
if: repo = pytest-dev/pytest-mock AND tag IS present
|
||||
|
||||
jobs:
|
||||
include:
|
||||
- python: '2.7'
|
||||
env: TOXENV=py27
|
||||
- python: '3.4'
|
||||
env: TOXENV=py34
|
||||
- python: '3.5'
|
||||
env: TOXENV=py35
|
||||
- python: '3.6'
|
||||
env: TOXENV=py36
|
||||
- python: '3.7'
|
||||
env: TOXENV=py37
|
||||
- python: '3.8-dev'
|
||||
env: TOXENV=py38
|
||||
- python: '3.6'
|
||||
env: TOXENV=linting
|
||||
- python: '3.6'
|
||||
|
|
|
@ -1,3 +1,52 @@
|
|||
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 <https://github.com/ambv/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
|
||||
-----
|
||||
|
||||
|
@ -300,13 +349,12 @@ First release.
|
|||
|
||||
.. _#2: https://github.com/pytest-dev/pytest-qt/issues/2
|
||||
|
||||
.. _@mathrick: https://github.com/mathrick
|
||||
.. _@tigarmo: https://github.com/tigarmo
|
||||
.. _@rouge8: https://github.com/rouge8
|
||||
.. _@fogo: https://github.com/fogo
|
||||
.. _@marcwebbie: https://github.com/marcwebbie
|
||||
.. _@RonnyPfannschmidt: https://github.com/RonnyPfannschmidt
|
||||
.. _@The-Compiler: https://github.com/The-Compiler
|
||||
.. _@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
|
||||
|
|
7
HOWTORELEASE.rst
Normal file
7
HOWTORELEASE.rst
Normal file
|
@ -0,0 +1,7 @@
|
|||
Here 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.
|
2
LICENSE
2
LICENSE
|
@ -18,4 +18,4 @@ 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.
|
||||
SOFTWARE.
|
||||
|
|
69
PKG-INFO
69
PKG-INFO
|
@ -1,12 +1,11 @@
|
|||
Metadata-Version: 1.2
|
||||
Metadata-Version: 2.1
|
||||
Name: pytest-mock
|
||||
Version: 1.7.1
|
||||
Version: 1.10.4
|
||||
Summary: Thin-wrapper around the mock package for easier use with py.test
|
||||
Home-page: https://github.com/pytest-dev/pytest-mock/
|
||||
Author: Bruno Oliveira
|
||||
Author-email: nicoddemus@gmail.com
|
||||
License: MIT
|
||||
Description-Content-Type: UNKNOWN
|
||||
Description: ===========
|
||||
pytest-mock
|
||||
===========
|
||||
|
@ -19,27 +18,26 @@ Description: ===========
|
|||
.. 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')
|
||||
|
||||
|
||||
.. Using PNG badges because PyPI doesn't support SVG
|
||||
|
||||
|python| |version| |anaconda| |ci| |appveyor| |coverage|
|
||||
|python| |version| |anaconda| |ci| |appveyor| |coverage| |black|
|
||||
|
||||
.. |version| image:: http://img.shields.io/pypi/v/pytest-mock.svg
|
||||
:target: https://pypi.python.org/pypi/pytest-mock
|
||||
|
||||
.. |anaconda| image:: https://anaconda.org/conda-forge/pytest-mock/badges/version.svg
|
||||
.. |anaconda| image:: https://img.shields.io/conda/vn/conda-forge/pytest-mock.svg
|
||||
:target: https://anaconda.org/conda-forge/pytest-mock
|
||||
|
||||
.. |ci| image:: http://img.shields.io/travis/pytest-dev/pytest-mock.svg
|
||||
|
@ -53,19 +51,17 @@ Description: ===========
|
|||
|
||||
.. |python| image:: https://img.shields.io/pypi/pyversions/pytest-mock.svg
|
||||
:target: https://pypi.python.org/pypi/pytest-mock/
|
||||
|
||||
|
||||
.. image:: http://www.opensourcecitizen.org/badge?url=github.com/pytest-dev/pytest-mock
|
||||
:target: http://www.opensourcecitizen.org/project?url=github.com/pytest-dev/pytest-mock
|
||||
|
||||
If you found this library useful, donate some CPU cycles to its
|
||||
development efforts by clicking above. Thank you! 😇
|
||||
.. |black| image:: https://img.shields.io/badge/code%20style-black-000000.svg
|
||||
:target: https://github.com/ambv/black
|
||||
|
||||
`Professionally supported pytest-mock is now available <https://tidelift.com/subscription/pkg/pypi-pytest_mock?utm_source=pypi-pytest-mock&utm_medium=referral&utm_campaign=readme>`_
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
The ``mocker`` fixture has the same API as
|
||||
`mock.patch <http://www.voidspace.org.uk/python/mock/patch.html#patch-decorators>`_,
|
||||
`mock.patch <https://docs.python.org/3/library/unittest.mock.html#patch>`_,
|
||||
supporting the same arguments:
|
||||
|
||||
.. code-block:: python
|
||||
|
@ -78,14 +74,14 @@ Description: ===========
|
|||
|
||||
The supported methods are:
|
||||
|
||||
* ``mocker.patch``: see http://www.voidspace.org.uk/python/mock/patch.html#patch.
|
||||
* ``mocker.patch.object``: see http://www.voidspace.org.uk/python/mock/patch.html#patch-object.
|
||||
* ``mocker.patch.multiple``: see http://www.voidspace.org.uk/python/mock/patch.html#patch-multiple.
|
||||
* ``mocker.patch.dict``: see http://www.voidspace.org.uk/python/mock/patch.html#patch-dict.
|
||||
* ``mocker.stopall()``: stops all active patches up to this point.
|
||||
* ``mocker.resetall()``: calls ``reset_mock()`` in all mocked objects up to this point.
|
||||
* `mocker.patch <https://docs.python.org/3/library/unittest.mock.html#patch>`_
|
||||
* `mocker.patch.object <https://docs.python.org/3/library/unittest.mock.html#patch-object>`_
|
||||
* `mocker.patch.multiple <https://docs.python.org/3/library/unittest.mock.html#patch-multiple>`_
|
||||
* `mocker.patch.dict <https://docs.python.org/3/library/unittest.mock.html#patch-dict>`_
|
||||
* `mocker.stopall <https://docs.python.org/3/library/unittest.mock.html#unittest.mock.patch.stopall>`_
|
||||
* ``mocker.resetall()``: calls `reset_mock() <https://docs.python.org/3/library/unittest.mock.html#unittest.mock.Mock.reset_mock>`_ in all mocked objects up to this point.
|
||||
|
||||
Some objects from the ``mock`` module are accessible directly from ``mocker`` for convenience:
|
||||
These objects from the ``mock`` module are accessible directly from ``mocker`` for convenience:
|
||||
|
||||
* `Mock <https://docs.python.org/3/library/unittest.mock.html#unittest.mock.Mock>`_
|
||||
* `MagicMock <https://docs.python.org/3/library/unittest.mock.html#unittest.mock.MagicMock>`_
|
||||
|
@ -169,8 +165,8 @@ Description: ===========
|
|||
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 ===========================
|
||||
|
||||
|
@ -331,6 +327,26 @@ Description: ===========
|
|||
return my_cm
|
||||
|
||||
|
||||
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 py27,py36,linting
|
||||
|
||||
Style checks and formatting are done automatically during commit courtesy of
|
||||
`pre-commit <https://pre-commit.com>`_.
|
||||
|
||||
License
|
||||
=======
|
||||
|
||||
|
@ -351,5 +367,8 @@ Classifier: Programming Language :: Python :: 3
|
|||
Classifier: Programming Language :: Python :: 3.4
|
||||
Classifier: Programming Language :: Python :: 3.5
|
||||
Classifier: Programming Language :: Python :: 3.6
|
||||
Classifier: Programming Language :: Python :: 3.7
|
||||
Classifier: Programming Language :: Python :: 3.8
|
||||
Classifier: Topic :: Software Development :: Testing
|
||||
Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
|
||||
Provides-Extra: dev
|
||||
|
|
61
README.rst
61
README.rst
|
@ -10,27 +10,26 @@ of a test:
|
|||
.. 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')
|
||||
|
||||
|
||||
.. Using PNG badges because PyPI doesn't support SVG
|
||||
|
||||
|python| |version| |anaconda| |ci| |appveyor| |coverage|
|
||||
|python| |version| |anaconda| |ci| |appveyor| |coverage| |black|
|
||||
|
||||
.. |version| image:: http://img.shields.io/pypi/v/pytest-mock.svg
|
||||
:target: https://pypi.python.org/pypi/pytest-mock
|
||||
|
||||
.. |anaconda| image:: https://anaconda.org/conda-forge/pytest-mock/badges/version.svg
|
||||
.. |anaconda| image:: https://img.shields.io/conda/vn/conda-forge/pytest-mock.svg
|
||||
:target: https://anaconda.org/conda-forge/pytest-mock
|
||||
|
||||
.. |ci| image:: http://img.shields.io/travis/pytest-dev/pytest-mock.svg
|
||||
|
@ -44,19 +43,17 @@ of a test:
|
|||
|
||||
.. |python| image:: https://img.shields.io/pypi/pyversions/pytest-mock.svg
|
||||
:target: https://pypi.python.org/pypi/pytest-mock/
|
||||
|
||||
|
||||
.. image:: http://www.opensourcecitizen.org/badge?url=github.com/pytest-dev/pytest-mock
|
||||
:target: http://www.opensourcecitizen.org/project?url=github.com/pytest-dev/pytest-mock
|
||||
|
||||
If you found this library useful, donate some CPU cycles to its
|
||||
development efforts by clicking above. Thank you! 😇
|
||||
.. |black| image:: https://img.shields.io/badge/code%20style-black-000000.svg
|
||||
:target: https://github.com/ambv/black
|
||||
|
||||
`Professionally supported pytest-mock is now available <https://tidelift.com/subscription/pkg/pypi-pytest_mock?utm_source=pypi-pytest-mock&utm_medium=referral&utm_campaign=readme>`_
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
The ``mocker`` fixture has the same API as
|
||||
`mock.patch <http://www.voidspace.org.uk/python/mock/patch.html#patch-decorators>`_,
|
||||
`mock.patch <https://docs.python.org/3/library/unittest.mock.html#patch>`_,
|
||||
supporting the same arguments:
|
||||
|
||||
.. code-block:: python
|
||||
|
@ -69,14 +66,14 @@ supporting the same arguments:
|
|||
|
||||
The supported methods are:
|
||||
|
||||
* ``mocker.patch``: see http://www.voidspace.org.uk/python/mock/patch.html#patch.
|
||||
* ``mocker.patch.object``: see http://www.voidspace.org.uk/python/mock/patch.html#patch-object.
|
||||
* ``mocker.patch.multiple``: see http://www.voidspace.org.uk/python/mock/patch.html#patch-multiple.
|
||||
* ``mocker.patch.dict``: see http://www.voidspace.org.uk/python/mock/patch.html#patch-dict.
|
||||
* ``mocker.stopall()``: stops all active patches up to this point.
|
||||
* ``mocker.resetall()``: calls ``reset_mock()`` in all mocked objects up to this point.
|
||||
* `mocker.patch <https://docs.python.org/3/library/unittest.mock.html#patch>`_
|
||||
* `mocker.patch.object <https://docs.python.org/3/library/unittest.mock.html#patch-object>`_
|
||||
* `mocker.patch.multiple <https://docs.python.org/3/library/unittest.mock.html#patch-multiple>`_
|
||||
* `mocker.patch.dict <https://docs.python.org/3/library/unittest.mock.html#patch-dict>`_
|
||||
* `mocker.stopall <https://docs.python.org/3/library/unittest.mock.html#unittest.mock.patch.stopall>`_
|
||||
* ``mocker.resetall()``: calls `reset_mock() <https://docs.python.org/3/library/unittest.mock.html#unittest.mock.Mock.reset_mock>`_ in all mocked objects up to this point.
|
||||
|
||||
Some objects from the ``mock`` module are accessible directly from ``mocker`` for convenience:
|
||||
These objects from the ``mock`` module are accessible directly from ``mocker`` for convenience:
|
||||
|
||||
* `Mock <https://docs.python.org/3/library/unittest.mock.html#unittest.mock.Mock>`_
|
||||
* `MagicMock <https://docs.python.org/3/library/unittest.mock.html#unittest.mock.MagicMock>`_
|
||||
|
@ -160,8 +157,8 @@ diff::
|
|||
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 ===========================
|
||||
|
||||
|
@ -322,6 +319,26 @@ temporarily:
|
|||
return my_cm
|
||||
|
||||
|
||||
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 py27,py36,linting
|
||||
|
||||
Style checks and formatting are done automatically during commit courtesy of
|
||||
`pre-commit <https://pre-commit.com>`_.
|
||||
|
||||
License
|
||||
=======
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# coding: utf-8
|
||||
# file generated by setuptools_scm
|
||||
# don't change, don't track in version control
|
||||
version = '1.7.1'
|
||||
version = '1.10.4'
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
install:
|
||||
- C:\Python36\python -m pip install tox
|
||||
- C:\Python37\python -m pip install -U pip
|
||||
- C:\Python37\python -m pip install tox
|
||||
|
||||
build: false # Not a C# project
|
||||
|
||||
test_script:
|
||||
- C:\Python36\scripts\tox
|
||||
- C:\Python37\scripts\tox
|
||||
|
||||
skip_tags: true
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
Metadata-Version: 1.2
|
||||
Metadata-Version: 2.1
|
||||
Name: pytest-mock
|
||||
Version: 1.7.1
|
||||
Version: 1.10.4
|
||||
Summary: Thin-wrapper around the mock package for easier use with py.test
|
||||
Home-page: https://github.com/pytest-dev/pytest-mock/
|
||||
Author: Bruno Oliveira
|
||||
Author-email: nicoddemus@gmail.com
|
||||
License: MIT
|
||||
Description-Content-Type: UNKNOWN
|
||||
Description: ===========
|
||||
pytest-mock
|
||||
===========
|
||||
|
@ -19,27 +18,26 @@ Description: ===========
|
|||
.. 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')
|
||||
|
||||
|
||||
.. Using PNG badges because PyPI doesn't support SVG
|
||||
|
||||
|python| |version| |anaconda| |ci| |appveyor| |coverage|
|
||||
|python| |version| |anaconda| |ci| |appveyor| |coverage| |black|
|
||||
|
||||
.. |version| image:: http://img.shields.io/pypi/v/pytest-mock.svg
|
||||
:target: https://pypi.python.org/pypi/pytest-mock
|
||||
|
||||
.. |anaconda| image:: https://anaconda.org/conda-forge/pytest-mock/badges/version.svg
|
||||
.. |anaconda| image:: https://img.shields.io/conda/vn/conda-forge/pytest-mock.svg
|
||||
:target: https://anaconda.org/conda-forge/pytest-mock
|
||||
|
||||
.. |ci| image:: http://img.shields.io/travis/pytest-dev/pytest-mock.svg
|
||||
|
@ -53,19 +51,17 @@ Description: ===========
|
|||
|
||||
.. |python| image:: https://img.shields.io/pypi/pyversions/pytest-mock.svg
|
||||
:target: https://pypi.python.org/pypi/pytest-mock/
|
||||
|
||||
|
||||
.. image:: http://www.opensourcecitizen.org/badge?url=github.com/pytest-dev/pytest-mock
|
||||
:target: http://www.opensourcecitizen.org/project?url=github.com/pytest-dev/pytest-mock
|
||||
|
||||
If you found this library useful, donate some CPU cycles to its
|
||||
development efforts by clicking above. Thank you! 😇
|
||||
.. |black| image:: https://img.shields.io/badge/code%20style-black-000000.svg
|
||||
:target: https://github.com/ambv/black
|
||||
|
||||
`Professionally supported pytest-mock is now available <https://tidelift.com/subscription/pkg/pypi-pytest_mock?utm_source=pypi-pytest-mock&utm_medium=referral&utm_campaign=readme>`_
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
The ``mocker`` fixture has the same API as
|
||||
`mock.patch <http://www.voidspace.org.uk/python/mock/patch.html#patch-decorators>`_,
|
||||
`mock.patch <https://docs.python.org/3/library/unittest.mock.html#patch>`_,
|
||||
supporting the same arguments:
|
||||
|
||||
.. code-block:: python
|
||||
|
@ -78,14 +74,14 @@ Description: ===========
|
|||
|
||||
The supported methods are:
|
||||
|
||||
* ``mocker.patch``: see http://www.voidspace.org.uk/python/mock/patch.html#patch.
|
||||
* ``mocker.patch.object``: see http://www.voidspace.org.uk/python/mock/patch.html#patch-object.
|
||||
* ``mocker.patch.multiple``: see http://www.voidspace.org.uk/python/mock/patch.html#patch-multiple.
|
||||
* ``mocker.patch.dict``: see http://www.voidspace.org.uk/python/mock/patch.html#patch-dict.
|
||||
* ``mocker.stopall()``: stops all active patches up to this point.
|
||||
* ``mocker.resetall()``: calls ``reset_mock()`` in all mocked objects up to this point.
|
||||
* `mocker.patch <https://docs.python.org/3/library/unittest.mock.html#patch>`_
|
||||
* `mocker.patch.object <https://docs.python.org/3/library/unittest.mock.html#patch-object>`_
|
||||
* `mocker.patch.multiple <https://docs.python.org/3/library/unittest.mock.html#patch-multiple>`_
|
||||
* `mocker.patch.dict <https://docs.python.org/3/library/unittest.mock.html#patch-dict>`_
|
||||
* `mocker.stopall <https://docs.python.org/3/library/unittest.mock.html#unittest.mock.patch.stopall>`_
|
||||
* ``mocker.resetall()``: calls `reset_mock() <https://docs.python.org/3/library/unittest.mock.html#unittest.mock.Mock.reset_mock>`_ in all mocked objects up to this point.
|
||||
|
||||
Some objects from the ``mock`` module are accessible directly from ``mocker`` for convenience:
|
||||
These objects from the ``mock`` module are accessible directly from ``mocker`` for convenience:
|
||||
|
||||
* `Mock <https://docs.python.org/3/library/unittest.mock.html#unittest.mock.Mock>`_
|
||||
* `MagicMock <https://docs.python.org/3/library/unittest.mock.html#unittest.mock.MagicMock>`_
|
||||
|
@ -169,8 +165,8 @@ Description: ===========
|
|||
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 ===========================
|
||||
|
||||
|
@ -331,6 +327,26 @@ Description: ===========
|
|||
return my_cm
|
||||
|
||||
|
||||
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 py27,py36,linting
|
||||
|
||||
Style checks and formatting are done automatically during commit courtesy of
|
||||
`pre-commit <https://pre-commit.com>`_.
|
||||
|
||||
License
|
||||
=======
|
||||
|
||||
|
@ -351,5 +367,8 @@ Classifier: Programming Language :: Python :: 3
|
|||
Classifier: Programming Language :: Python :: 3.4
|
||||
Classifier: Programming Language :: Python :: 3.5
|
||||
Classifier: Programming Language :: Python :: 3.6
|
||||
Classifier: Programming Language :: Python :: 3.7
|
||||
Classifier: Programming Language :: Python :: 3.8
|
||||
Classifier: Topic :: Software Development :: Testing
|
||||
Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
|
||||
Provides-Extra: dev
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
.gitignore
|
||||
.pre-commit-config.yaml
|
||||
.travis.yml
|
||||
CHANGELOG.rst
|
||||
HOWTORELEASE.rst
|
||||
LICENSE
|
||||
README.rst
|
||||
_pytest_mock_version.py
|
||||
|
|
|
@ -2,3 +2,7 @@ pytest>=2.7
|
|||
|
||||
[:python_version < "3.0"]
|
||||
mock
|
||||
|
||||
[dev]
|
||||
pre-commit
|
||||
tox
|
||||
|
|
117
pytest_mock.py
117
pytest_mock.py
|
@ -22,13 +22,17 @@ def _get_mock_module(config):
|
|||
"unittest.mock" for Python 3, but the user can force to always use "mock" on Python 3 using
|
||||
the mock_use_standalone_module ini option.
|
||||
"""
|
||||
if not hasattr(_get_mock_module, '_module'):
|
||||
use_standalone_module = parse_ini_boolean(config.getini('mock_use_standalone_module'))
|
||||
if not hasattr(_get_mock_module, "_module"):
|
||||
use_standalone_module = parse_ini_boolean(
|
||||
config.getini("mock_use_standalone_module")
|
||||
)
|
||||
if sys.version_info[0] == 2 or use_standalone_module:
|
||||
import mock
|
||||
|
||||
_get_mock_module._module = mock
|
||||
else:
|
||||
import unittest.mock
|
||||
|
||||
_get_mock_module._module = unittest.mock
|
||||
|
||||
return _get_mock_module._module
|
||||
|
@ -48,10 +52,12 @@ class MockFixture(object):
|
|||
# aliases for convenience
|
||||
self.Mock = mock_module.Mock
|
||||
self.MagicMock = mock_module.MagicMock
|
||||
self.NonCallableMock = mock_module.NonCallableMock
|
||||
self.PropertyMock = mock_module.PropertyMock
|
||||
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
|
||||
|
||||
|
@ -98,8 +104,7 @@ class MockFixture(object):
|
|||
if isinstance(value, (classmethod, staticmethod)):
|
||||
autospec = False
|
||||
|
||||
result = self.patch.object(obj, name, side_effect=method,
|
||||
autospec=autospec)
|
||||
result = self.patch.object(obj, name, side_effect=method, autospec=autospec)
|
||||
return result
|
||||
|
||||
def stub(self, name=None):
|
||||
|
@ -132,7 +137,7 @@ class MockFixture(object):
|
|||
p = mock_func(*args, **kwargs)
|
||||
mocked = p.start()
|
||||
self._patches.append(p)
|
||||
if hasattr(mocked, 'reset_mock'):
|
||||
if hasattr(mocked, "reset_mock"):
|
||||
self._mocks.append(mocked)
|
||||
return mocked
|
||||
|
||||
|
@ -142,8 +147,7 @@ class MockFixture(object):
|
|||
|
||||
def multiple(self, *args, **kwargs):
|
||||
"""API to mock.patch.multiple"""
|
||||
return self._start_patch(self.mock_module.patch.multiple, *args,
|
||||
**kwargs)
|
||||
return self._start_patch(self.mock_module.patch.multiple, *args, **kwargs)
|
||||
|
||||
def dict(self, *args, **kwargs):
|
||||
"""API to mock.patch.dict"""
|
||||
|
@ -171,8 +175,10 @@ def mock(mocker):
|
|||
Same as "mocker", but kept only for backward compatibility.
|
||||
"""
|
||||
import warnings
|
||||
warnings.warn('"mock" fixture has been deprecated, use "mocker" instead',
|
||||
DeprecationWarning)
|
||||
|
||||
warnings.warn(
|
||||
'"mock" fixture has been deprecated, use "mocker" instead', DeprecationWarning
|
||||
)
|
||||
return mocker
|
||||
|
||||
|
||||
|
@ -186,22 +192,22 @@ def assert_wrapper(__wrapped_mock_method__, *args, **kwargs):
|
|||
__wrapped_mock_method__(*args, **kwargs)
|
||||
return
|
||||
except AssertionError as e:
|
||||
if getattr(e, '_mock_introspection_applied', 0):
|
||||
if getattr(e, "_mock_introspection_applied", 0):
|
||||
msg = text_type(e)
|
||||
else:
|
||||
__mock_self = args[0]
|
||||
msg = text_type(e)
|
||||
if __mock_self.call_args is not None:
|
||||
actual_args, actual_kwargs = __mock_self.call_args
|
||||
msg += '\n\npytest introspection follows:\n'
|
||||
msg += "\n\npytest introspection follows:\n"
|
||||
try:
|
||||
assert actual_args == args[1:]
|
||||
except AssertionError as e:
|
||||
msg += '\nArgs:\n' + text_type(e)
|
||||
msg += "\nArgs:\n" + text_type(e)
|
||||
try:
|
||||
assert actual_kwargs == kwargs
|
||||
except AssertionError as e:
|
||||
msg += '\nKwargs:\n' + text_type(e)
|
||||
msg += "\nKwargs:\n" + text_type(e)
|
||||
e = AssertionError(msg)
|
||||
e._mock_introspection_applied = True
|
||||
raise e
|
||||
|
@ -209,32 +215,37 @@ def assert_wrapper(__wrapped_mock_method__, *args, **kwargs):
|
|||
|
||||
def wrap_assert_not_called(*args, **kwargs):
|
||||
__tracebackhide__ = True
|
||||
assert_wrapper(_mock_module_originals["assert_not_called"],
|
||||
*args, **kwargs)
|
||||
assert_wrapper(_mock_module_originals["assert_not_called"], *args, **kwargs)
|
||||
|
||||
|
||||
def wrap_assert_called_with(*args, **kwargs):
|
||||
__tracebackhide__ = True
|
||||
assert_wrapper(_mock_module_originals["assert_called_with"],
|
||||
*args, **kwargs)
|
||||
assert_wrapper(_mock_module_originals["assert_called_with"], *args, **kwargs)
|
||||
|
||||
|
||||
def wrap_assert_called_once(*args, **kwargs):
|
||||
__tracebackhide__ = True
|
||||
assert_wrapper(_mock_module_originals["assert_called_once"], *args, **kwargs)
|
||||
|
||||
|
||||
def wrap_assert_called_once_with(*args, **kwargs):
|
||||
__tracebackhide__ = True
|
||||
assert_wrapper(_mock_module_originals["assert_called_once_with"],
|
||||
*args, **kwargs)
|
||||
assert_wrapper(_mock_module_originals["assert_called_once_with"], *args, **kwargs)
|
||||
|
||||
|
||||
def wrap_assert_has_calls(*args, **kwargs):
|
||||
__tracebackhide__ = True
|
||||
assert_wrapper(_mock_module_originals["assert_has_calls"],
|
||||
*args, **kwargs)
|
||||
assert_wrapper(_mock_module_originals["assert_has_calls"], *args, **kwargs)
|
||||
|
||||
|
||||
def wrap_assert_any_call(*args, **kwargs):
|
||||
__tracebackhide__ = True
|
||||
assert_wrapper(_mock_module_originals["assert_any_call"],
|
||||
*args, **kwargs)
|
||||
assert_wrapper(_mock_module_originals["assert_any_call"], *args, **kwargs)
|
||||
|
||||
|
||||
def wrap_assert_called(*args, **kwargs):
|
||||
__tracebackhide__ = True
|
||||
assert_wrapper(_mock_module_originals["assert_called"], *args, **kwargs)
|
||||
|
||||
|
||||
def wrap_assert_methods(config):
|
||||
|
@ -249,11 +260,13 @@ def wrap_assert_methods(config):
|
|||
mock_module = _get_mock_module(config)
|
||||
|
||||
wrappers = {
|
||||
'assert_not_called': wrap_assert_not_called,
|
||||
'assert_called_with': wrap_assert_called_with,
|
||||
'assert_called_once_with': wrap_assert_called_once_with,
|
||||
'assert_has_calls': wrap_assert_has_calls,
|
||||
'assert_any_call': wrap_assert_any_call,
|
||||
"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:
|
||||
|
@ -261,12 +274,11 @@ def wrap_assert_methods(config):
|
|||
except AttributeError: # pragma: no cover
|
||||
continue
|
||||
_mock_module_originals[method] = original
|
||||
patcher = mock_module.patch.object(
|
||||
mock_module.NonCallableMock, method, wrapper)
|
||||
patcher = mock_module.patch.object(mock_module.NonCallableMock, method, wrapper)
|
||||
patcher.start()
|
||||
_mock_module_patches.append(patcher)
|
||||
|
||||
if hasattr(config, 'add_cleanup'):
|
||||
if hasattr(config, "add_cleanup"):
|
||||
add_cleanup = config.add_cleanup
|
||||
else:
|
||||
# pytest 2.7 compatibility
|
||||
|
@ -276,32 +288,49 @@ def wrap_assert_methods(config):
|
|||
|
||||
def unwrap_assert_methods():
|
||||
for patcher in _mock_module_patches:
|
||||
patcher.stop()
|
||||
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 text_type(e) == "stop called on unstarted patcher":
|
||||
pass
|
||||
else:
|
||||
raise
|
||||
_mock_module_patches[:] = []
|
||||
_mock_module_originals.clear()
|
||||
|
||||
|
||||
def pytest_addoption(parser):
|
||||
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)
|
||||
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 parse_ini_boolean(value):
|
||||
if value in (True, False):
|
||||
return value
|
||||
try:
|
||||
return {'true': True, 'false': False}[value.lower()]
|
||||
return {"true": True, "false": False}[value.lower()]
|
||||
except KeyError:
|
||||
raise ValueError('unknown string for bool: %r' % value)
|
||||
raise ValueError("unknown string for bool: %r" % value)
|
||||
|
||||
|
||||
def pytest_configure(config):
|
||||
tb = config.getoption('--tb')
|
||||
if parse_ini_boolean(config.getini('mock_traceback_monkeypatch')) and tb != 'native':
|
||||
tb = config.getoption("--tb", default="auto")
|
||||
if (
|
||||
parse_ini_boolean(config.getini("mock_traceback_monkeypatch"))
|
||||
and tb != "native"
|
||||
):
|
||||
wrap_assert_methods(config)
|
||||
|
|
66
setup.py
66
setup.py
|
@ -1,40 +1,38 @@
|
|||
from setuptools import setup
|
||||
|
||||
from io import open
|
||||
|
||||
from setuptools import setup
|
||||
|
||||
setup(
|
||||
name='pytest-mock',
|
||||
entry_points={
|
||||
'pytest11': ['pytest_mock = pytest_mock'],
|
||||
},
|
||||
py_modules=['pytest_mock', '_pytest_mock_version'],
|
||||
platforms='any',
|
||||
python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*',
|
||||
install_requires=[
|
||||
'pytest>=2.7',
|
||||
'mock;python_version<"3.0"',
|
||||
],
|
||||
use_scm_version={'write_to': '_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 py.test',
|
||||
long_description=open('README.rst', encoding='utf-8').read(),
|
||||
name="pytest-mock",
|
||||
entry_points={"pytest11": ["pytest_mock = pytest_mock"]},
|
||||
py_modules=["pytest_mock", "_pytest_mock_version"],
|
||||
platforms="any",
|
||||
python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*",
|
||||
install_requires=["pytest>=2.7", 'mock;python_version<"3.0"'],
|
||||
use_scm_version={"write_to": "_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 py.test",
|
||||
long_description=open("README.rst", encoding="utf-8").read(),
|
||||
keywords="pytest mock",
|
||||
extras_require={"dev": ["pre-commit", "tox"]},
|
||||
classifiers=[
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
'Framework :: Pytest',
|
||||
'Intended Audience :: Developers',
|
||||
'License :: OSI Approved :: MIT License',
|
||||
'Operating System :: OS Independent',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.4',
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Topic :: Software Development :: Testing',
|
||||
]
|
||||
"Development Status :: 5 - Production/Stable",
|
||||
"Framework :: Pytest",
|
||||
"Intended Audience :: Developers",
|
||||
"License :: OSI Approved :: MIT License",
|
||||
"Operating System :: OS Independent",
|
||||
"Programming Language :: Python :: 2",
|
||||
"Programming Language :: Python :: 2.7",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.4",
|
||||
"Programming Language :: Python :: 3.5",
|
||||
"Programming Language :: Python :: 3.6",
|
||||
"Programming Language :: Python :: 3.7",
|
||||
"Programming Language :: Python :: 3.8",
|
||||
"Topic :: Software Development :: Testing",
|
||||
],
|
||||
)
|
||||
|
|
|
@ -6,11 +6,15 @@ from contextlib import contextmanager
|
|||
import py.code
|
||||
import pytest
|
||||
|
||||
pytest_plugins = 'pytester'
|
||||
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 work on pypy')
|
||||
skip_pypy = pytest.mark.skipif(
|
||||
platform.python_implementation() == "PyPy", reason="could not make work on pypy"
|
||||
)
|
||||
|
||||
# Python 3.8 changed the output formatting (bpo-35500).
|
||||
PY38 = sys.version_info >= (3, 8)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
@ -20,10 +24,12 @@ def needs_assert_rewrite(pytestconfig):
|
|||
|
||||
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))
|
||||
option = pytestconfig.getoption("assertmode")
|
||||
if option != "rewrite":
|
||||
pytest.skip(
|
||||
"this test needs assertion rewrite to work but current option "
|
||||
'is "{}"'.format(option)
|
||||
)
|
||||
|
||||
|
||||
class UnixFS(object):
|
||||
|
@ -52,20 +58,20 @@ def check_unix_fs_mocked(tmpdir, mocker):
|
|||
assert mocked_rm is os.remove
|
||||
assert mocked_ls is os.listdir
|
||||
|
||||
file_name = tmpdir / 'foo.txt'
|
||||
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.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']
|
||||
assert UnixFS.ls(str(tmpdir)) == ["foo.txt"]
|
||||
UnixFS.rm(str(file_name))
|
||||
assert not os.path.isfile(str(file_name))
|
||||
|
||||
|
@ -73,21 +79,20 @@ def check_unix_fs_mocked(tmpdir, mocker):
|
|||
|
||||
|
||||
def mock_using_patch_object(mocker):
|
||||
return mocker.patch.object(os, 'remove'), mocker.patch.object(os, 'listdir')
|
||||
return mocker.patch.object(os, "remove"), mocker.patch.object(os, "listdir")
|
||||
|
||||
|
||||
def mock_using_patch(mocker):
|
||||
return mocker.patch('os.remove'), mocker.patch('os.listdir')
|
||||
return mocker.patch("os.remove"), mocker.patch("os.listdir")
|
||||
|
||||
|
||||
def mock_using_patch_multiple(mocker):
|
||||
r = mocker.patch.multiple('os', remove=mocker.DEFAULT,
|
||||
listdir=mocker.DEFAULT)
|
||||
return r['remove'], r['listdir']
|
||||
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],
|
||||
@pytest.mark.parametrize(
|
||||
"mock_fs", [mock_using_patch_object, mock_using_patch, mock_using_patch_multiple]
|
||||
)
|
||||
def test_mock_patches(mock_fs, mocker, check_unix_fs_mocked):
|
||||
"""
|
||||
|
@ -108,11 +113,11 @@ def test_mock_patch_dict(mocker):
|
|||
Testing
|
||||
:param mock:
|
||||
"""
|
||||
x = {'original': 1}
|
||||
mocker.patch.dict(x, values=[('new', 10)], clear=True)
|
||||
assert x == {'new': 10}
|
||||
x = {"original": 1}
|
||||
mocker.patch.dict(x, values=[("new", 10)], clear=True)
|
||||
assert x == {"new": 10}
|
||||
mocker.stopall()
|
||||
assert x == {'original': 1}
|
||||
assert x == {"original": 1}
|
||||
|
||||
|
||||
def test_mock_patch_dict_resetall(mocker):
|
||||
|
@ -120,24 +125,49 @@ def test_mock_patch_dict_resetall(mocker):
|
|||
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}
|
||||
x = {"original": 1}
|
||||
mocker.patch.dict(x, values=[("new", 10)], clear=True)
|
||||
assert x == {"new": 10}
|
||||
mocker.resetall()
|
||||
assert x == {'new': 10}
|
||||
assert x == {"new": 10}
|
||||
|
||||
|
||||
def test_deprecated_mock(mock, tmpdir):
|
||||
def test_deprecated_mock(testdir):
|
||||
"""
|
||||
Use backward-compatibility-only mock fixture to ensure complete coverage.
|
||||
"""
|
||||
mock.patch('os.listdir', return_value=['mocked'])
|
||||
assert os.listdir(str(tmpdir)) == ['mocked']
|
||||
mock.stopall()
|
||||
assert os.listdir(str(tmpdir)) == []
|
||||
p1 = testdir.makepyfile(
|
||||
"""
|
||||
import os
|
||||
|
||||
def test(mock, tmpdir):
|
||||
mock.patch("os.listdir", return_value=["mocked"])
|
||||
assert os.listdir(str(tmpdir)) == ["mocked"]
|
||||
mock.stopall()
|
||||
assert os.listdir(str(tmpdir)) == []
|
||||
"""
|
||||
)
|
||||
result = testdir.runpytest(str(p1))
|
||||
result.stdout.fnmatch_lines(
|
||||
['*DeprecationWarning: "mock" fixture has been deprecated, use "mocker"*']
|
||||
)
|
||||
assert result.ret == 0
|
||||
|
||||
|
||||
@pytest.mark.parametrize('name', ['MagicMock', 'PropertyMock', 'Mock', 'call', 'ANY', 'sentinel', 'mock_open'])
|
||||
@pytest.mark.parametrize(
|
||||
"name",
|
||||
[
|
||||
"ANY",
|
||||
"call",
|
||||
"create_autospec",
|
||||
"MagicMock",
|
||||
"Mock",
|
||||
"mock_open",
|
||||
"NonCallableMock",
|
||||
"PropertyMock",
|
||||
"sentinel",
|
||||
],
|
||||
)
|
||||
def test_mocker_aliases(name, pytestconfig):
|
||||
from pytest_mock import _get_mock_module, MockFixture
|
||||
|
||||
|
@ -148,8 +178,8 @@ def test_mocker_aliases(name, pytestconfig):
|
|||
|
||||
|
||||
def test_mocker_resetall(mocker):
|
||||
listdir = mocker.patch('os.listdir')
|
||||
open = mocker.patch('os.open')
|
||||
listdir = mocker.patch("os.listdir")
|
||||
open = mocker.patch("os.open")
|
||||
|
||||
listdir("/tmp")
|
||||
open("/tmp/foo.txt")
|
||||
|
@ -165,21 +195,25 @@ def test_mocker_resetall(mocker):
|
|||
class TestMockerStub:
|
||||
def test_call(self, mocker):
|
||||
stub = mocker.stub()
|
||||
stub('foo', 'bar')
|
||||
stub.assert_called_once_with('foo', 'bar')
|
||||
stub("foo", "bar")
|
||||
stub.assert_called_once_with("foo", "bar")
|
||||
|
||||
def test_repr_with_no_name(self, mocker):
|
||||
stub = mocker.stub()
|
||||
assert not 'name' in repr(stub)
|
||||
assert "name" not in repr(stub)
|
||||
|
||||
def test_repr_with_name(self, mocker):
|
||||
test_name = 'funny walk'
|
||||
test_name = "funny walk"
|
||||
stub = mocker.stub(name=test_name)
|
||||
assert "name={0!r}".format(test_name) in repr(stub)
|
||||
|
||||
def __test_failure_message(self, mocker, **kwargs):
|
||||
expected_name = kwargs.get('name') or 'mock'
|
||||
expected_message = 'Expected call: {0}()\nNot called'.format(expected_name)
|
||||
expected_name = kwargs.get("name") or "mock"
|
||||
if PY38:
|
||||
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()
|
||||
|
@ -188,20 +222,19 @@ class TestMockerStub:
|
|||
def test_failure_message_with_no_name(self, mocker):
|
||||
self.__test_failure_message(mocker)
|
||||
|
||||
@pytest.mark.parametrize('name', (None, '', 'f', 'The Castle of aaarrrrggh'))
|
||||
@pytest.mark.parametrize("name", (None, "", "f", "The Castle of aaarrrrggh"))
|
||||
def test_failure_message_with_name(self, mocker, name):
|
||||
self.__test_failure_message(mocker, name=name)
|
||||
|
||||
|
||||
def test_instance_method_spy(mocker):
|
||||
class Foo(object):
|
||||
|
||||
def bar(self, arg):
|
||||
return arg * 2
|
||||
|
||||
foo = Foo()
|
||||
other = Foo()
|
||||
spy = mocker.spy(foo, 'bar')
|
||||
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)
|
||||
|
@ -211,11 +244,10 @@ def test_instance_method_spy(mocker):
|
|||
@skip_pypy
|
||||
def test_instance_method_by_class_spy(mocker):
|
||||
class Foo(object):
|
||||
|
||||
def bar(self, arg):
|
||||
return arg * 2
|
||||
|
||||
spy = mocker.spy(Foo, 'bar')
|
||||
spy = mocker.spy(Foo, "bar")
|
||||
foo = Foo()
|
||||
other = Foo()
|
||||
assert foo.bar(arg=10) == 20
|
||||
|
@ -226,16 +258,14 @@ def test_instance_method_by_class_spy(mocker):
|
|||
|
||||
@skip_pypy
|
||||
def test_instance_method_by_subclass_spy(mocker):
|
||||
|
||||
class Base(object):
|
||||
|
||||
def bar(self, arg):
|
||||
return arg * 2
|
||||
|
||||
class Foo(Base):
|
||||
pass
|
||||
|
||||
spy = mocker.spy(Foo, 'bar')
|
||||
spy = mocker.spy(Foo, "bar")
|
||||
foo = Foo()
|
||||
other = Foo()
|
||||
assert foo.bar(arg=10) == 20
|
||||
|
@ -247,22 +277,20 @@ def test_instance_method_by_subclass_spy(mocker):
|
|||
@skip_pypy
|
||||
def test_class_method_spy(mocker):
|
||||
class Foo(object):
|
||||
|
||||
@classmethod
|
||||
def bar(cls, arg):
|
||||
return arg * 2
|
||||
|
||||
spy = mocker.spy(Foo, 'bar')
|
||||
spy = mocker.spy(Foo, "bar")
|
||||
assert Foo.bar(arg=10) == 20
|
||||
Foo.bar.assert_called_once_with(arg=10)
|
||||
spy.assert_called_once_with(arg=10)
|
||||
|
||||
|
||||
@skip_pypy
|
||||
@pytest.mark.xfail(sys.version_info[0] == 2, reason='does not work on Python 2')
|
||||
@pytest.mark.xfail(sys.version_info[0] == 2, reason="does not work on Python 2")
|
||||
def test_class_method_subclass_spy(mocker):
|
||||
class Base(object):
|
||||
|
||||
@classmethod
|
||||
def bar(self, arg):
|
||||
return arg * 2
|
||||
|
@ -270,7 +298,7 @@ def test_class_method_subclass_spy(mocker):
|
|||
class Foo(Base):
|
||||
pass
|
||||
|
||||
spy = mocker.spy(Foo, 'bar')
|
||||
spy = mocker.spy(Foo, "bar")
|
||||
assert Foo.bar(arg=10) == 20
|
||||
Foo.bar.assert_called_once_with(arg=10)
|
||||
spy.assert_called_once_with(arg=10)
|
||||
|
@ -289,7 +317,7 @@ def test_class_method_with_metaclass_spy(mocker):
|
|||
def bar(cls, arg):
|
||||
return arg * 2
|
||||
|
||||
spy = mocker.spy(Foo, 'bar')
|
||||
spy = mocker.spy(Foo, "bar")
|
||||
assert Foo.bar(arg=10) == 20
|
||||
Foo.bar.assert_called_once_with(arg=10)
|
||||
spy.assert_called_once_with(arg=10)
|
||||
|
@ -298,22 +326,20 @@ def test_class_method_with_metaclass_spy(mocker):
|
|||
@skip_pypy
|
||||
def test_static_method_spy(mocker):
|
||||
class Foo(object):
|
||||
|
||||
@staticmethod
|
||||
def bar(arg):
|
||||
return arg * 2
|
||||
|
||||
spy = mocker.spy(Foo, 'bar')
|
||||
spy = mocker.spy(Foo, "bar")
|
||||
assert Foo.bar(arg=10) == 20
|
||||
Foo.bar.assert_called_once_with(arg=10)
|
||||
spy.assert_called_once_with(arg=10)
|
||||
|
||||
|
||||
@skip_pypy
|
||||
@pytest.mark.xfail(sys.version_info[0] == 2, reason='does not work on Python 2')
|
||||
@pytest.mark.xfail(sys.version_info[0] == 2, reason="does not work on Python 2")
|
||||
def test_static_method_subclass_spy(mocker):
|
||||
class Base(object):
|
||||
|
||||
@staticmethod
|
||||
def bar(arg):
|
||||
return arg * 2
|
||||
|
@ -321,7 +347,7 @@ def test_static_method_subclass_spy(mocker):
|
|||
class Foo(Base):
|
||||
pass
|
||||
|
||||
spy = mocker.spy(Foo, 'bar')
|
||||
spy = mocker.spy(Foo, "bar")
|
||||
assert Foo.bar(arg=10) == 20
|
||||
Foo.bar.assert_called_once_with(arg=10)
|
||||
spy.assert_called_once_with(arg=10)
|
||||
|
@ -352,17 +378,20 @@ def assert_argument_introspection(left, right):
|
|||
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))
|
||||
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")
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info[:2] == (3, 4),
|
||||
reason="assert_not_called not available in Python 3.4")
|
||||
@pytest.mark.skipif(
|
||||
sys.version_info[:2] == (3, 4),
|
||||
reason="assert_not_called not available in Python 3.4",
|
||||
)
|
||||
def test_assert_not_called_wrapper(mocker):
|
||||
stub = mocker.stub()
|
||||
stub.assert_not_called()
|
||||
|
@ -388,12 +417,35 @@ def test_assert_called_once_with_wrapper(mocker):
|
|||
stub.assert_called_once_with("foo")
|
||||
|
||||
|
||||
@pytest.mark.usefixtures('needs_assert_rewrite')
|
||||
def test_assert_called_once_wrapper(mocker):
|
||||
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):
|
||||
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):
|
||||
stub = mocker.stub()
|
||||
|
||||
complex_args = ('a', 1, set(['test']))
|
||||
wrong_args = ('b', 2, set(['jest']))
|
||||
complex_args = ("a", 1, set(["test"]))
|
||||
wrong_args = ("b", 2, set(["jest"]))
|
||||
|
||||
stub(*complex_args)
|
||||
stub.assert_called_with(*complex_args)
|
||||
|
@ -404,12 +456,12 @@ def test_assert_called_args_with_introspection(mocker):
|
|||
stub.assert_called_once_with(*wrong_args)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures('needs_assert_rewrite')
|
||||
@pytest.mark.usefixtures("needs_assert_rewrite")
|
||||
def test_assert_called_kwargs_with_introspection(mocker):
|
||||
stub = mocker.stub()
|
||||
|
||||
complex_kwargs = dict(foo={'bar': 1, 'baz': 'spam'})
|
||||
wrong_kwargs = dict(foo={'goo': 1, 'baz': 'bran'})
|
||||
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)
|
||||
|
@ -442,26 +494,31 @@ def test_monkeypatch_ini(mocker, testdir):
|
|||
stub = mocker.stub()
|
||||
assert stub.assert_called_with.__module__ != stub.__module__
|
||||
|
||||
testdir.makepyfile("""
|
||||
testdir.makepyfile(
|
||||
"""
|
||||
import py.code
|
||||
def test_foo(mocker):
|
||||
stub = mocker.stub()
|
||||
assert stub.assert_called_with.__module__ == stub.__module__
|
||||
""")
|
||||
testdir.makeini("""
|
||||
"""
|
||||
)
|
||||
testdir.makeini(
|
||||
"""
|
||||
[pytest]
|
||||
mock_traceback_monkeypatch = false
|
||||
""")
|
||||
"""
|
||||
)
|
||||
result = runpytest_subprocess(testdir)
|
||||
assert result.ret == 0
|
||||
|
||||
|
||||
def test_parse_ini_boolean():
|
||||
import pytest_mock
|
||||
assert pytest_mock.parse_ini_boolean('True') is True
|
||||
assert pytest_mock.parse_ini_boolean('false') is False
|
||||
|
||||
assert pytest_mock.parse_ini_boolean("True") is True
|
||||
assert pytest_mock.parse_ini_boolean("false") is False
|
||||
with pytest.raises(ValueError):
|
||||
pytest_mock.parse_ini_boolean('foo')
|
||||
pytest_mock.parse_ini_boolean("foo")
|
||||
|
||||
|
||||
def test_patched_method_parameter_name(mocker):
|
||||
|
@ -474,73 +531,109 @@ def test_patched_method_parameter_name(mocker):
|
|||
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'})
|
||||
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):
|
||||
"""Automatically disable monkeypatching when --tb=native.
|
||||
"""
|
||||
testdir.makepyfile("""
|
||||
testdir.makepyfile(
|
||||
"""
|
||||
def test_foo(mocker):
|
||||
stub = mocker.stub()
|
||||
stub(1, greet='hello')
|
||||
stub.assert_called_once_with(1, greet='hey')
|
||||
""")
|
||||
result = runpytest_subprocess(testdir, '--tb=native')
|
||||
"""
|
||||
)
|
||||
result = runpytest_subprocess(testdir, "--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)
|
||||
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)
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info[0] < 3, reason='Py3 only')
|
||||
def test_monkeypatch_no_terminal(testdir):
|
||||
"""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 = runpytest_subprocess(testdir, "-p", "no:terminal", "-s")
|
||||
assert result.ret == 1
|
||||
assert result.stdout.lines == []
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info[0] < 3, reason="Py3 only")
|
||||
def test_standalone_mock(testdir):
|
||||
"""Check that the "mock_use_standalone" is being used.
|
||||
"""
|
||||
testdir.makepyfile("""
|
||||
testdir.makepyfile(
|
||||
"""
|
||||
def test_foo(mocker):
|
||||
pass
|
||||
""")
|
||||
testdir.makeini("""
|
||||
"""
|
||||
)
|
||||
testdir.makeini(
|
||||
"""
|
||||
[pytest]
|
||||
mock_use_standalone_module = true
|
||||
""")
|
||||
"""
|
||||
)
|
||||
result = runpytest_subprocess(testdir)
|
||||
assert result.ret == 3
|
||||
result.stderr.fnmatch_lines([
|
||||
"*No module named 'mock'*",
|
||||
])
|
||||
result.stderr.fnmatch_lines(["*No module named 'mock'*"])
|
||||
|
||||
|
||||
def runpytest_subprocess(testdir, *args):
|
||||
"""Testdir.runpytest_subprocess only available in pytest-2.8+"""
|
||||
if hasattr(testdir, 'runpytest_subprocess'):
|
||||
if hasattr(testdir, "runpytest_subprocess"):
|
||||
return testdir.runpytest_subprocess(*args)
|
||||
else:
|
||||
# pytest 2.7.X
|
||||
return testdir.runpytest(*args)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures('needs_assert_rewrite')
|
||||
@pytest.mark.usefixtures("needs_assert_rewrite")
|
||||
def test_detailed_introspection(testdir):
|
||||
"""Check that the "mock_use_standalone" is being used.
|
||||
"""
|
||||
testdir.makepyfile("""
|
||||
testdir.makepyfile(
|
||||
"""
|
||||
def test(mocker):
|
||||
m = mocker.Mock()
|
||||
m('fo')
|
||||
m.assert_called_once_with('', bar=4)
|
||||
""")
|
||||
result = testdir.runpytest('-s')
|
||||
result.stdout.fnmatch_lines([
|
||||
"*AssertionError: Expected call: mock('', bar=4)*",
|
||||
"*Actual call: mock('fo')*",
|
||||
"""
|
||||
)
|
||||
result = testdir.runpytest("-s")
|
||||
if PY38:
|
||||
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:',
|
||||
"*Args:",
|
||||
"*assert ('fo',) == ('',)",
|
||||
"*At index 0 diff: 'fo' != ''*",
|
||||
"*Use -v to get the full diff*",
|
||||
|
@ -549,14 +642,35 @@ def test_detailed_introspection(testdir):
|
|||
"*Right contains more items:*",
|
||||
"*{'bar': 4}*",
|
||||
"*Use -v to get the full diff*",
|
||||
])
|
||||
]
|
||||
result.stdout.fnmatch_lines(expected_lines)
|
||||
|
||||
|
||||
def test_assert_called_with_unicode_arguments(mocker):
|
||||
"""Test bug in assert_call_with called with non-ascii unicode string (#91)"""
|
||||
stub = mocker.stub()
|
||||
stub(b'l\xc3\xb6k'.decode('UTF-8'))
|
||||
stub(b"l\xc3\xb6k".decode("UTF-8"))
|
||||
|
||||
with pytest.raises(AssertionError):
|
||||
stub.assert_called_with(u'lak')
|
||||
stub.assert_called_with(u"lak")
|
||||
|
||||
|
||||
def test_plain_stopall(testdir):
|
||||
"""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()
|
||||
|
|
26
tox.ini
26
tox.ini
|
@ -1,15 +1,10 @@
|
|||
[tox]
|
||||
envlist = py{27,34,35,36}-pytest{30,31,32,33,34},linting,norewrite
|
||||
envlist = py{27,34,35,36,37}, linting, norewrite
|
||||
|
||||
[testenv]
|
||||
passenv = USER USERNAME
|
||||
deps =
|
||||
coverage
|
||||
pytest30: pytest~=3.0
|
||||
pytest31: pytest~=3.1
|
||||
pytest32: pytest~=3.2
|
||||
pytest33: pytest~=3.3
|
||||
pytest34: pytest~=3.4
|
||||
commands =
|
||||
coverage run --append --source=pytest_mock.py -m pytest test_pytest_mock.py
|
||||
|
||||
|
@ -18,11 +13,14 @@ commands =
|
|||
pytest test_pytest_mock.py --assert=plain -ra
|
||||
|
||||
[testenv:linting]
|
||||
skip_install=True
|
||||
deps =
|
||||
pytest-flakes
|
||||
restructuredtext_lint
|
||||
pygments
|
||||
commands =
|
||||
py.test --flakes pytest_mock.py test_pytest_mock.py -m flakes
|
||||
rst-lint CHANGELOG.rst README.rst
|
||||
skipsdist = True
|
||||
usedevelop = True
|
||||
extras = dev
|
||||
basepython = python3.6
|
||||
commands = pre-commit run --all-files --show-diff-on-failure
|
||||
|
||||
[pytest]
|
||||
addopts = -ra
|
||||
|
||||
[flake8]
|
||||
max-line-length = 88
|
||||
|
|
Loading…
Reference in a new issue