Skip to content

Deprecate mock in favor of mocker #5

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Sep 17, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 24 additions & 13 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@
pytest-mock
===========

This plugin installs a ``mock`` fixture which is a thin-wrapper around the patching API
This plugin installs a ``mocker`` fixture which is a thin-wrapper around the patching API
provided by the excellent `mock <http://pypi.python.org/pypi/mock>`_ package,
but with the benefit of not having to worry about undoing patches at the end
of a test:

.. code-block:: python


def test_unix_fs(mock):
mock.patch('os.remove')
def test_unix_fs(mocker):
mocker.patch('os.remove')
UnixFS.rm('file')
os.remove.assert_called_once_with('file')

Expand Down Expand Up @@ -40,27 +40,38 @@ of a test:
Usage
=====

The ``mock`` fixture has the same API as
The ``mocker`` fixture has the same API as
`mock.patch <http://www.voidspace.org.uk/python/mock/patch.html#patch-decorators>`_,
supporting the same arguments:

.. code-block:: python

def test_foo(mock):
def test_foo(mocker):
# all valid calls
mock.patch('os.remove')
mock.patch.object(os, 'listdir', autospec=True)
mocked = mock.patch('os.path.isfile')
mocker.patch('os.remove')
mocker.patch.object(os, 'listdir', autospec=True)
mocked_isfile = mocker.patch('os.path.isfile')

The supported methods are:

* ``mock.patch``: see http://www.voidspace.org.uk/python/mock/patch.html#patch.
* ``mock.patch.object``: see http://www.voidspace.org.uk/python/mock/patch.html#patch-object.
* ``mock.patch.multiple``: see http://www.voidspace.org.uk/python/mock/patch.html#patch-multiple.
* ``mock.patch.dict``: see http://www.voidspace.org.uk/python/mock/patch.html#patch-dict.
* ``mock.stopall()``: stops all active patches at this point.
* ``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 at this point.


Note
----

Prior to version ``0.4.0``, the ``mocker`` fixture was named ``mock``.
This was changed because naming the fixture ``mock`` conflicts with the
actual ``mock`` module, which made using it awkward when access to both the
module and the plugin were required within a test.

The old fixture ``mock`` still works, but its use is discouraged and will be
removed in version ``1.0``.

Requirements
============

Expand Down
16 changes: 14 additions & 2 deletions pytest_mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,23 @@ def __call__(self, *args, **kwargs):


@pytest.yield_fixture
def mock():
def mocker():
"""
return an object that has the same interface to the `mock` module, but
takes care of automatically undoing all patches after each test method.
"""
result = MockFixture()
yield result
result.stopall()
result.stopall()


@pytest.yield_fixture
def mock():
"""
Same as "mocker", but kept only for backward compatibility.
"""
import warnings
warnings.warn('"mock" fixture has been deprecated, use "mocker" instead',
DeprecationWarning)
for m in mocker():
yield m
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

setup(
name='pytest-mock',
version='0.3.0',
version='0.4.0',
entry_points={
'pytest11': ['pytest-mock = pytest_mock'],
},
Expand Down
52 changes: 37 additions & 15 deletions test_pytest_mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import pytest


pytest_plugins = 'pytester'

class UnixFS(object):
"""
Wrapper to os functions to simulate a Unix file system, used for testing
Expand All @@ -19,7 +21,7 @@ def ls(cls, path):


@pytest.fixture
def check_unix_fs_mocked(tmpdir, mock):
def check_unix_fs_mocked(tmpdir, mocker):
"""
performs a standard test in a UnixFS, assuming that both `os.remove` and
`os.listdir` have been mocked previously.
Expand All @@ -40,7 +42,7 @@ def check(mocked_rm, mocked_ls):
assert UnixFS.ls(str(tmpdir)) == ['bar.txt']
mocked_ls.assert_called_once_with(str(tmpdir))

mock.stopall()
mocker.stopall()

assert UnixFS.ls(str(tmpdir)) == ['foo.txt']
UnixFS.rm(str(file_name))
Expand All @@ -49,43 +51,63 @@ def check(mocked_rm, mocked_ls):
return check


def mock_using_patch_object(mock):
return mock.patch.object(os, 'remove'), mock.patch.object(os, 'listdir')
def mock_using_patch_object(mocker):
return mocker.patch.object(os, 'remove'), mocker.patch.object(os, 'listdir')


def mock_using_patch(mock):
return mock.patch('os.remove'), mock.patch('os.listdir')
def mock_using_patch(mocker):
return mocker.patch('os.remove'), mocker.patch('os.listdir')


def mock_using_patch_multiple(mock):
def mock_using_patch_multiple(mocker):
from pytest_mock import mock_module

r = mock.patch.multiple('os', remove=mock_module.DEFAULT,
listdir=mock_module.DEFAULT)
r = mocker.patch.multiple('os', remove=mock_module.DEFAULT,
listdir=mock_module.DEFAULT)
return r['remove'], r['listdir']


@pytest.mark.parametrize('mock_fs', [mock_using_patch_object, mock_using_patch,
mock_using_patch_multiple],
)
def test_mock_patches(mock_fs, mock, check_unix_fs_mocked):
def test_mock_patches(mock_fs, mocker, check_unix_fs_mocked):
"""
Installs mocks into `os` functions and performs a standard testing of
mock functionality. We parametrize different mock methods to ensure
all (intended, at least) mock API is covered.
"""
mock_fs(mock)
mocked_rm, mocked_ls = mock_fs(mock)
# mock it twice on purpose to ensure we unmock it correctly later
mock_fs(mocker)
mocked_rm, mocked_ls = mock_fs(mocker)
check_unix_fs_mocked(mocked_rm, mocked_ls)


def test_mock_patch_dict(mock):
def test_mock_patch_dict(mocker):
"""
Testing
:param mock:
"""
x = {'original': 1}
mock.patch.dict(x, values=[('new', 10)], clear=True)
mocker.patch.dict(x, values=[('new', 10)], clear=True)
assert x == {'new': 10}
mock.stopall()
mocker.stopall()
assert x == {'original': 1}


def test_mock_fixture_is_deprecated(testdir):
"""
Test that a warning emitted when using deprecated "mock" fixture.
"""
testdir.makepyfile('''
import warnings
import os
warnings.simplefilter('always')

def test_foo(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('-s')
result.stderr.fnmatch_lines(['*"mock" fixture has been deprecated*'])