kaste / mockito-python

Mockito is a spying framework
MIT License
123 stars 12 forks source link

Issue unstubbing random.randint #53

Closed PatrikBernhard closed 2 years ago

PatrikBernhard commented 2 years ago

When trying to monkeypatch random.randint and then later unstubbing the original method does not get reinstated. Example:

import sys
sys.version
Out[3]: '3.10.4 (main, Mar 31 2022, 03:38:35) [Clang 12.0.0 ]'
import random
import mockito
mockito.__version__
Out[6]: '1.2.2'
random.randint(1, 10)
Out[7]: 6
mockito.when(random).randint(...).thenReturn("Mocked!")
Out[8]: <mockito.invocation.AnswerSelector at 0x7ff076012c80>
random.randint(1, 10)
Out[9]: 'Mocked!'
mockito.unstub()
random.randint(1, 10)
Traceback (most recent call last):
...
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "<ipython-input-11-a5705e42ffa6>", line 1, in <cell line: 1>
    random.randint(1, 10)
AttributeError: module 'random' has no attribute 'randint'`

This seems to be because:

not inspect.isclass(self.mocked_obj) and inspect.ismethod(original_method)

in the method restore_method within mocking returns True when it should be False.

kaste commented 2 years ago

Yes, that looks like a bug. The isclass check here is suspicious. How could we have a bound method, t.i. ismethod is True on a class, t.i. also isclass is True? 🤔

We can probably just add and not ismodule(mocked_obj) here; not sure why I don't get the logic here simpler. All we need is to decide if we added the method/function either because it wasn't there in the first place or because we wanted to hide the original implementation which still lives on the class ("prototype") and all the other instances of it.

kaste commented 2 years ago

I released this as a hotfix v1.3.3 Thanks for opening the issue.