From 35cbb5791d143cf5c552e92f46e18b15e7385ac7 Mon Sep 17 00:00:00 2001 From: Ronny Pfannschmidt Date: Tue, 25 Sep 2012 18:15:13 +0200 Subject: [PATCH] fixes issue 156: monkeypatch class level descriptors --- CHANGELOG | 3 ++- _pytest/monkeypatch.py | 6 +++++- testing/test_monkeypatch.py | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 497c4d939..7de71184e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -56,7 +56,8 @@ Changes between 2.2.4 and 2.3.0.dev - fix issue 188: ensure sys.exc_info is clear on python2 before calling into a test -- fix issue 191: addd unittest TestCase runTest method support +- fix issue 191: add unittest TestCase runTest method support +- fix issue 156: monkeypatch correctly handles class level descriptors - reporting refinements: diff --git a/_pytest/monkeypatch.py b/_pytest/monkeypatch.py index 862904431..292e4f76e 100644 --- a/_pytest/monkeypatch.py +++ b/_pytest/monkeypatch.py @@ -1,6 +1,6 @@ """ monkeypatching and mocking functionality. """ -import os, sys +import os, sys, inspect def pytest_funcarg__monkeypatch(request): """The returned ``monkeypatch`` funcarg provides these @@ -39,6 +39,10 @@ class monkeypatch: oldval = getattr(obj, name, notset) if raising and oldval is notset: raise AttributeError("%r has no attribute %r" %(obj, name)) + + # avoid class descriptors like staticmethod/classmethod + if inspect.isclass(obj): + oldval = obj.__dict__.get(name, notset) self._setattr.insert(0, (obj, name, oldval)) setattr(obj, name, value) diff --git a/testing/test_monkeypatch.py b/testing/test_monkeypatch.py index 1fafb73e5..7a6150d0e 100644 --- a/testing/test_monkeypatch.py +++ b/testing/test_monkeypatch.py @@ -206,3 +206,38 @@ def test_issue185_time_breaks(testdir): result.stdout.fnmatch_lines(""" *1 passed* """) + + + +class SampleNew(object): + @staticmethod + def hello(): + return True + + +class SampleNewInherit(SampleNew): + pass + + +class SampleOld: + #oldstyle on python2 + @staticmethod + def hello(): + return True + +class SampleOldInherit(SampleOld): + pass + + +@pytest.mark.parametrize('Sample', [ + SampleNew, SampleNewInherit, + SampleOld, SampleOldInherit, +], ids=['new', 'new-inherit', 'old', 'old-inherit']) +def test_issue156_undo_staticmethod(Sample): + monkeypatch = MonkeyPatch() + + monkeypatch.setattr(Sample, 'hello', None) + assert Sample.hello is None + + monkeypatch.undo() + assert Sample.hello()