New upstream version 1.10.4

This commit is contained in:
Ondřej Nový 2019-08-24 18:33:04 +02:00
parent cde0d28bf2
commit e5f34a66ea
16 changed files with 583 additions and 289 deletions

22
.pre-commit-config.yaml Normal file
View 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

View file

@ -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'

View file

@ -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
View 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.

View file

@ -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.

View file

@ -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

View file

@ -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
=======

View file

@ -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'

View file

@ -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

View file

@ -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

View file

@ -1,6 +1,8 @@
.gitignore
.pre-commit-config.yaml
.travis.yml
CHANGELOG.rst
HOWTORELEASE.rst
LICENSE
README.rst
_pytest_mock_version.py

View file

@ -2,3 +2,7 @@ pytest>=2.7
[:python_version < "3.0"]
mock
[dev]
pre-commit
tox

View file

@ -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)

View file

@ -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",
],
)

View file

@ -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
View file

@ -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