I have been wondering about this behaviour when replacing a class method I observe in Python 3.8 and concluded I do not understand it. I suspect it may have something to do with loosing the @classmethod
decorator or something similar, but am at a loss.
What exactly is going wrong there?
What is a good way to make the last case work without using mocking libraries?
Note: I know the code below is not the best practice. This is about trying to learn more about Python and understanding what is going on under the hood.
from unittest import mock
class SomeClass:
@classmethod
def hello(cls) -> str:
return cls.__name__
class DerivedClass(SomeClass):
pass
def test_works_as_expected():
assert SomeClass.hello() == 'SomeClass' # True
assert DerivedClass.hello() == 'DerivedClass' # True
def test_replace_with_mock():
# This works just fine
assert DerivedClass.hello() == 'DerivedClass' # True
with mock.patch.object(SomeClass, 'hello', new=lambda: 'replacement'):
assert DerivedClass.hello() == 'replacement' # True
assert DerivedClass.hello() == 'DerivedClass' # True
def test_this_does_not_work():
assert DerivedClass.hello() == 'DerivedClass' # True
original_fn = SomeClass.hello
SomeClass.hello = lambda: 'replacement'
assert DerivedClass.hello() == 'replacement' # True
SomeClass.hello = original_fn # This should put things back in order, but does not
assert DerivedClass.hello() == 'DerivedClass' # AssertionError: assert 'SomeClass' == 'DerivedClass'
# After executing the above DerivedClass.hello() no longer works correctly in this module or in any other