diff --git a/_pytest/python.py b/_pytest/python.py index 8a3fcd51a..ac981ddb1 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -1861,6 +1861,29 @@ class FixtureDef: return ("" % (self.argname, self.scope, self.baseid)) +def handle_mock_module_patching(function, startindex): + """ + Special treatment when test_function is decorated + by mock.patch + """ + for candidate_module_name in ('mock', 'unittest.mock'): + # stdlib comes last, because mock might be also installed + # as a third party with upgraded version compare to + # unittest.mock + try: + mock = sys.modules[candidate_module_name] + except KeyError: + pass + else: + for patching in getattr(function, "patchings", []): + if (not patching.attribute_name + and patching.new is mock.DEFAULT): + startindex += 1 + break + else: + startindex += len(getattr(function, "patchings", [])) + return startindex + def getfuncargnames(function, startindex=None): # XXX merge with main.py's varnames #assert not inspect.isclass(function) @@ -1870,13 +1893,7 @@ def getfuncargnames(function, startindex=None): if startindex is None: startindex = inspect.ismethod(function) and 1 or 0 if realfunction != function: - mock = sys.modules.get('mock') - if mock is not None: - for patching in getattr(function, "patchings", []): - if not patching.attribute_name and patching.new is mock.DEFAULT: - startindex += 1 - else: - startindex += len(getattr(function, "patchings", [])) + startindex = handle_mock_module_patching(function, startindex) function = realfunction argnames = inspect.getargs(py.code.getrawcode(function))[0] defaults = getattr(function, 'func_defaults', diff --git a/testing/python/integration.py b/testing/python/integration.py index e27f27d52..6b389776b 100644 --- a/testing/python/integration.py +++ b/testing/python/integration.py @@ -112,6 +112,26 @@ class TestMockDecoration: reprec = testdir.inline_run() reprec.assertoutcome(passed=1) + def test_unittest_mock_and_fixture(self, testdir): + pytest.importorskip("unittest.mock") + testdir.makepyfile(""" + import os.path + import unittest.mock + import pytest + + @pytest.fixture + def inject_me(): + pass + + @unittest.mock.patch.object(os.path, "abspath", + new=unittest.mock.MagicMock) + def test_hello(inject_me): + import os + os.path.abspath("hello") + """) + reprec = testdir.inline_run() + reprec.assertoutcome(passed=1) + def test_mock(self, testdir): pytest.importorskip("mock", "1.0.1") testdir.makepyfile("""