From 0dd378da307adef2af5902e8cb5fade2ea0f45ec Mon Sep 17 00:00:00 2001 From: Nicolas Delaby Date: Sat, 26 Jul 2014 17:26:18 +0200 Subject: [PATCH 1/3] Injection of fixture doesn't work when decorated with unittest.mock.patch This is a continuation of #182 --HG-- branch : mock-unittest-252 --- testing/python/integration.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) 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(""" From e6ad6e02d234e09e7ebee741d7b5a4aa8e609ff9 Mon Sep 17 00:00:00 2001 From: Nicolas Delaby Date: Sun, 27 Jul 2014 10:43:50 +0200 Subject: [PATCH 2/3] Handle also unittest.mock Move handling in dedicated function to isolate its logic --HG-- branch : mock-unittest-252 --- _pytest/python.py | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/_pytest/python.py b/_pytest/python.py index 8a3fcd51a..2ddf83ef9 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -1861,6 +1861,27 @@ 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 ('unittest.mock', 'mock'): + # stdlib comes first + 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 +1891,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', From 2e55c4ba61a67275fe594a14f5deccca1c923d76 Mon Sep 17 00:00:00 2001 From: Nicolas Delaby Date: Sun, 27 Jul 2014 12:11:39 +0200 Subject: [PATCH 3/3] unittest.mock from stdlib should come last --HG-- branch : mock-unittest-252 --- _pytest/python.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/_pytest/python.py b/_pytest/python.py index 2ddf83ef9..ac981ddb1 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -1866,8 +1866,10 @@ def handle_mock_module_patching(function, startindex): Special treatment when test_function is decorated by mock.patch """ - for candidate_module_name in ('unittest.mock', 'mock'): - # stdlib comes first + 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: