Skip to main content

Thin-wrapper around the mock package for easier use with py.test

Project description

This plugin installs a mocker fixture which is a thin-wrapper around the patching API provided by the mock package, but with the benefit of not having to worry about undoing patches at the end of a test:

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

python version downloads ci appveyor coverage

Usage

The mocker fixture has the same API as mock.patch, supporting the same arguments:

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

The supported methods are:

Some objects from the mock module are accessible directly from mocker for convenience:

Spy

The spy acts exactly like the original method in all cases, except it allows use of mock features with it, like retrieving call count. It also works for class and static methods.

def test_spy(mocker):
    class Foo(object):
        def bar(self):
            return 42

    foo = Foo()
    mocker.spy(foo, 'bar')
    assert foo.bar() == 42
    assert foo.bar.call_count == 1

Stub

The stub is a mock object that accepts any arguments and is useful to test callbacks, for instance. May be passed a name to be used by the constructed stub object in its repr (useful for debugging).

def test_stub(mocker):
    def foo(on_something):
        on_something('foo', 'bar')

    stub = mocker.stub(name='on_something_stub')

    foo(stub)
    stub.assert_called_once_with('foo', 'bar')

Improved reporting of mock call assertion errors

This plugin monkeypatches the mock library to improve pytest output for failures of mock call assertions like Mock.assert_called_with() by hiding internal traceback entries from the mock module.

It also adds introspection information on differing call arguments when calling the helper methods. This features catches AssertionError raised in the method, and uses py.test’s own advanced assertions to return a better diff:

        m = mocker.patch.object(DS, 'create_char')
        DS().create_char('Raistlin', class_='mag', gift=12)
>       m.assert_called_once_with('Raistlin', class_='mage', gift=12)
E       assert {'class_': 'mag', 'gift': 12} == {'class_': 'mage', 'gift': 12}
E         Omitting 1 identical items, use -v to show
E         Differing items:
E         {'class_': 'mag'} != {'class_': 'mage'}
E         Use -v to get the full diff

This is useful when asserting mock calls with many/nested arguments and trying to quickly see the difference.

This feature is probably safe, but if you encounter any problems it can be disabled in your pytest.ini file:

[pytest]
mock_traceback_monkeypatch = false

Note that this feature is automatically disabled with the --tb=native option. The underlying mechanism used to suppress traceback entries from mock module does not work with that option anyway plus it generates confusing messages on Python 3.5 due to exception chaining

Requirements

  • Python 2.6+, Python 3.3+

  • pytest

  • mock (for Python 2)

Install

Install using pip:

$ pip install pytest-mock

Changelog

Please consult the changelog page.

Why bother with a plugin?

There are a number of different patch usages in the standard mock API, but IMHO they don’t scale very well when you have more than one or two patches to apply.

It may lead to an excessive nesting of with statements, breaking the flow of the test:

import mock

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

        with mock.patch('os.listdir'):
            assert UnixFS.ls('dir') == expected
            # ...

    with mock.patch('shutil.copy'):
        UnixFS.cp('src', 'dst')
        # ...

One can use patch as a decorator to improve the flow of the test:

@mock.patch('os.remove')
@mock.patch('os.listdir')
@mock.patch('shutil.copy')
def test_unix_fs(mocked_copy, mocked_listdir, mocked_remove):
    UnixFS.rm('file')
    os.remove.assert_called_once_with('file')

    assert UnixFS.ls('dir') == expected
    # ...

    UnixFS.cp('src', 'dst')
    # ...

But this poses a few disadvantages:

  • test functions must receive the mock objects as parameter, even if you don’t plan to access them directly; also, order depends on the order of the decorated patch functions;

  • receiving the mocks as parameters doesn’t mix nicely with pytest’s approach of naming fixtures as parameters, or pytest.mark.parametrize;

  • you can’t easily undo the mocking during the test execution;

Note

Although mocker’s API is intentionally the same as mock.patch’s, its uses as context managers and function decorators are not supported. The purpose of this plugin is to make the use of context managers and function decorators for mocking unnecessary. Indeed, trying to use the functionality in mocker in this manner can lead to non-intuitive errors:

def test_context_manager(mocker):
    a = A()
    with mocker.patch.object(a, 'doIt', return_value=True, autospec=True):
        assert a.doIt() == True
================================== FAILURES ===================================
____________________________ test_context_manager _____________________________
in test_context_manager
    with mocker.patch.object(a, 'doIt', return_value=True, autospec=True):
E   AttributeError: __exit__

License

Distributed under the terms of the MIT license.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pytest-mock-1.2.zip (19.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pytest_mock-1.2-py2.py3-none-any.whl (11.0 kB view details)

Uploaded Python 2Python 3

File details

Details for the file pytest-mock-1.2.zip.

File metadata

  • Download URL: pytest-mock-1.2.zip
  • Upload date:
  • Size: 19.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No

File hashes

Hashes for pytest-mock-1.2.zip
Algorithm Hash digest
SHA256 f78971ed376fcb265255d1e4bb313731b3a1be92d7f3ecb19ea7fedc4a56fd0f
MD5 a7fa820f7bc71698660945836ff93c73
BLAKE2b-256 3011a5a8009eff04bc15c37e2f8e33d8ed99adf828ec8f551fb31d99f6c73b5b

See more details on using hashes here.

File details

Details for the file pytest_mock-1.2-py2.py3-none-any.whl.

File metadata

File hashes

Hashes for pytest_mock-1.2-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 2911668c5ea518a07e2da53a170e2f86eaccf1245ec9605c37eadf6578dec468
MD5 e696587f17c787c5b52035b58658b41d
BLAKE2b-256 6a40d5f2fbef42f85b8c53ddb2bb1db847ef46c86e6204abfeaa605b3ed07307

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page