将Python模拟的autospec用于对象方法的正确方法是什么?

时间:2019-02-15 16:49:37

标签: python python-3.x unit-testing mocking

在模拟对象的方法时尝试使用autospec=True时出现错误。我将写下一个简单的示例,展示如何重现我得到的错误。假设我有一个非常简单的类,如下所示:

class SimpleClass:

    def target_method(self, a, b):
        return a + b

现在,在系统的另一部分中,我有一个通过执行SimpleClassprint(obj.target_method(a, b))实例进行交互的函数,并且我必须对该函数进行统一测试。我想通过用target_method模拟autospec=True来测试它,以确保方法签名并检查它是否按预期被调用。当我收到如下所述的错误消息时:

In [24]: with patch.object(SimpleClass, 'target_method', autospec=True) as mock: 
    ...:     mock(2, 5) 
    ...:                                                                                                 
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-24-04b2a0db8a31> in <module>
      1 with patch.object(SimpleClass, 'target_method', autospec=True) as mock:
----> 2     mock(2, 5)
      3 

<string> in target_method(*args, **kwargs)

/usr/lib/python3.6/unittest/mock.py in checksig(*args, **kwargs)
    169     func, sig = result
    170     def checksig(*args, **kwargs):
--> 171         sig.bind(*args, **kwargs)
    172     _copy_func_details(func, checksig)
    173 

/usr/lib/python3.6/inspect.py in bind(*args, **kwargs)
   2987         if the passed arguments can not be bound.
   2988         """
-> 2989         return args[0]._bind(args[1:], kwargs)
   2990 
   2991     def bind_partial(*args, **kwargs):

/usr/lib/python3.6/inspect.py in _bind(self, args, kwargs, partial)
   2902                             msg = 'missing a required argument: {arg!r}'
   2903                             msg = msg.format(arg=param.name)
-> 2904                             raise TypeError(msg) from None
   2905             else:
   2906                 # We have a positional argument to process

TypeError: missing a required argument: 'b'

如果我做对了,mock会将自己作为独立函数执行,并且这样做需要显式传递self参数。

所以,我的问题是在修补对象的方法时是否有一种方法可以使用autospec而不会出现此异常。

1 个答案:

答案 0 :(得分:3)

您应该调用实例化对象的方法:

with patch.object(SimpleClass, 'target_method', autospec=True): 
    obj = SimpleClass()
    obj.target_method(2, 5)

https://docs.python.org/3/library/unittest.mock.html#unittest.mock.patch.object

中所述