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)