pytest-mock/test_pytest_mock.py
2015-10-09 23:24:37 +02:00

234 lines
6.1 KiB
Python

import os
import platform
import pytest
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')
class UnixFS(object):
"""
Wrapper to os functions to simulate a Unix file system, used for testing
the mock fixture.
"""
@classmethod
def rm(cls, filename):
os.remove(filename)
@classmethod
def ls(cls, path):
return os.listdir(path)
@pytest.fixture
def check_unix_fs_mocked(tmpdir, mocker):
"""
performs a standard test in a UnixFS, assuming that both `os.remove` and
`os.listdir` have been mocked previously.
"""
def check(mocked_rm, mocked_ls):
assert mocked_rm is os.remove
assert mocked_ls is os.listdir
file_name = tmpdir / 'foo.txt'
file_name.ensure()
UnixFS.rm(str(file_name))
mocked_rm.assert_called_once_with(str(file_name))
assert os.path.isfile(str(file_name))
mocked_ls.return_value = ['bar.txt']
assert UnixFS.ls(str(tmpdir)) == ['bar.txt']
mocked_ls.assert_called_once_with(str(tmpdir))
mocker.stopall()
assert UnixFS.ls(str(tmpdir)) == ['foo.txt']
UnixFS.rm(str(file_name))
assert not os.path.isfile(str(file_name))
return check
def mock_using_patch_object(mocker):
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')
def mock_using_patch_multiple(mocker):
from pytest_mock import mock_module
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, 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 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(mocker):
"""
Testing
:param mock:
"""
x = {'original': 1}
mocker.patch.dict(x, values=[('new', 10)], clear=True)
assert x == {'new': 10}
mocker.stopall()
assert x == {'original': 1}
def test_mock_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*'])
def test_deprecated_mock(mock, tmpdir):
"""
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)) == []
def test_mocker_has_magic_mock_class_as_attribute_for_instantiation():
from pytest_mock import mock_module, MockFixture
mocker = MockFixture()
assert isinstance(mocker.MagicMock(), mock_module.MagicMock)
def test_mocker_has_mock_class_as_attribute_for_instantiation():
from pytest_mock import mock_module, MockFixture
mocker = MockFixture()
assert isinstance(mocker.Mock(), mock_module.Mock)
def test_mocker_stub(mocker):
def foo(on_something):
on_something('foo', 'bar')
stub = mocker.stub()
foo(stub)
stub.assert_called_once_with('foo', 'bar')
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')
assert foo.bar(arg=10) == 20
assert other.bar(arg=10) == 20
foo.bar.assert_called_once_with(arg=10)
spy.assert_called_once_with(arg=10)
@skip_pypy
def test_instance_method_by_class_spy(mocker):
from pytest_mock import mock_module
class Foo(object):
def bar(self, arg):
return arg * 2
spy = mocker.spy(Foo, 'bar')
foo = Foo()
other = Foo()
assert foo.bar(arg=10) == 20
assert other.bar(arg=10) == 20
calls = [mock_module.call(foo, arg=10), mock_module.call(other, arg=10)]
assert spy.call_args_list == calls
@skip_pypy
def test_class_method_spy(mocker):
class Foo(object):
@classmethod
def bar(cls, arg):
return arg * 2
spy = mocker.spy(Foo, 'bar')
assert Foo.bar(arg=10) == 20
Foo.bar.assert_called_once_with(arg=10)
spy.assert_called_once_with(arg=10)
@skip_pypy
def test_class_method_with_metaclass_spy(mocker):
class MetaFoo(type):
pass
class Foo(object):
__metaclass__ = MetaFoo
@classmethod
def bar(cls, arg):
return arg * 2
spy = mocker.spy(Foo, 'bar')
assert Foo.bar(arg=10) == 20
Foo.bar.assert_called_once_with(arg=10)
spy.assert_called_once_with(arg=10)
@skip_pypy
def test_static_method_spy(mocker):
class Foo(object):
@staticmethod
def bar(arg):
return arg * 2
spy = mocker.spy(Foo, 'bar')
assert Foo.bar(arg=10) == 20
Foo.bar.assert_called_once_with(arg=10)
spy.assert_called_once_with(arg=10)