简体   繁体   中英

python check if a method is called without mocking it away

class A():
    def tmp(self):
        print("hi")

def b(a):
    a.tmp()

To check if tmp method is called in b, the recommended way is

a = A()
a.tmp = MagicMock()
b(a)
a.tmp.assert_called()

But tmp here is being mocked away and is not resulting in a "hi" getting printed.

I would want my unit test to check if method tmp is called without mocking it away.

Is this possible?

I know this is not a standard thing to expect when writing unitests. But my use case (which is bit tricky) requires this.

You can set the Mock.side_effect to be the original method.

from unittest.mock import MagicMock

class A():
    def tmp(self):
        print("hi")

def b(a):
    a.tmp()

a = A()
a.tmp = MagicMock(side_effect=a.tmp)
b(a)
a.tmp.assert_called()

When side_effect is a function (or a bound method in this case, which is a kind of function), calling the Mock will also call the side_effect with the same arguments.

The Mock() call will return whatever the side_effect returns, unless it returns the unnittest.mock.DEFAULT singleton. Then it will return Mock.return_value instead.

Or you can decorate the method to test:

def check_called(fun):
    def wrapper(self, *args, **kw):
        attrname = "_{}_called".format(fun.__name__)
        setattr(self, attrname, True)
        return fun(self, *args, **kw)
    return wrapper


a = A()
a.tmp = check_called(a.tmp)
b(a)
assert(getattr(a, "_tmp_called", False))

but MagicMock's side_effect is definitly a better solution if you're already using Mock ;)

In addition to @Patrick Haugh's answer , you can also pass the function to the wraps argument (and it seems more semantically correct to me).

wraps: Item for the mock object to wrap. If wraps is not None then calling the Mock will pass the call through to the wrapped object (returning the real result). Attribute access on the mock will return a Mock object that wraps the corresponding attribute of the wrapped object (so attempting to access an attribute that doesn't exist will raise an AttributeError).

a = A()
a.tmp = MagicMock(wraps=a.tmp)
b(a)
a.tmp.assert_called()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM