Search code examples
pythontestingmockingself

How I can access the object's "self" from a mock method in minimock


In Python, I want to mock the __init__ method of a class using the minimock library.

This is what the interpreter does (ipython):

In [1]: import minimock

In [2]: class A:
   ...:     def __init__(self):
   ...:         print "REAL INIT"
   ...:

In [3]: def new_init(self):
   ...:     print "NEW INIT"
   ...:

In [4]: minimock.mock("A.__init__", returns_func=new_init)

In [5]: a = A()
Called A.__init__()
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-5-144b248f218a> in <module>()
----> 1 a = A()

D:\Tools\Python27\lib\site-packages\minimock\__init__.pyc in __call__(self, *args, **kw)
    492         if self.mock_tracker is not None:
    493             self.mock_tracker.call(self.mock_name, *args, **kw)
--> 494         return self._mock_return(*args, **kw)
    495
    496     def _mock_return(self, *args, **kw):

D:\Tools\Python27\lib\site-packages\minimock\__init__.pyc in _mock_return(self, *args, **kw)
    505                 raise Exception("No more mock return values are present.")
    506         elif self.mock_returns_func is not None:
--> 507             return self.mock_returns_func(*args, **kw)
    508         else:
    509             return None

TypeError: new_init() takes exactly 1 argument (0 given)

However, if I remove the self argument from new_init:

def new_init():
    print "NEW INIT"

Instantiating the A class gives:

In [13]: a = A()
Called A.__init__()
NEW INIT

Which leads me to think that minimock has limitations with "self".

Do you know if it is possible to use "self" in the mocked versions of methods passed to minimock?


Solution

  • I really don't understand why you are doing that, anyway the answer is that you should not call A.__init__ directly:

    >>> class A(object):
    ...     def __init__(self):
    ...             print('Old init - self' + str(self))
    >>> def new_init(self):
    ...     print('New init - self:' + str(self))
    ... 
    >>> A.__init__ = new_init
    >>> A.__init__()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: unbound method new_init() must be called with A instance as first argument (got nothing instead)
    >>> A()
    New init - self:<__main__.A object at 0x2446d90>
    <__main__.A object at 0x2446d90>
    

    The minimock library does nothing wrong. __init__ is meant to be called by calling the class. If you call it explicitly then you must pass explicitly an instance as first argument.

    Anyway I'd strongly suggest you to think again of what you are doing because you shouldn't do something like this. Mocks should be used to mock entire objects, not just a method. In your case I'd mock the entire class A and not only it's __init__ method.