简体   繁体   English

不使用self调用带有side_effect的对象方法的python补丁

[英]python patch with side_effect on Object's method is not called with self

I encounter a surprising behaviour of the side_effect parameter in patch.object where the function replacing the original does not receive self 我在patch.object中遇到了side_effect参数的令人惊讶的行为,其中替换原始函数的函数没有收到self

class Animal():
    def __init__(self):
        self.noise = 'Woof'

    def make_noise(self):
        return self.noise

def loud(self):
    return self.noise.upper() + '!!'


from unittest.mock import patch

dog = Animal()
dog.make_noise()
with patch.object(Animal, 'make_noise', side_effect=loud):
    dog.make_noise()

This give: 这给:

Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "/lustre/home/production/Applications/python/python-3.4.4/lib/python3.4/unittest/mock.py", line 902, in __call__
    return _mock_self._mock_call(*args, **kwargs)
  File "/lustre/home/production/Applications/python/python-3.4.4/lib/python3.4/unittest/mock.py", line 968, in _mock_call
    ret_val = effect(*args, **kwargs)
TypeError: loud() missing 1 required positional argument: 'self'

If I change the loud function to 如果我将loud功能更改为

def loud(*args, **kwargs):
    print(args)
    print(kwargs)

I get the following output: 我得到以下输出:

()
{}

Is there a way to replace a function from an object and still receive self? 有没有办法从一个对象替换一个函数,仍然接收自己?

self is only supplied for bound methods (because functions are descriptors ). self仅为绑定方法提供 (因为函数是描述符 )。 A Mock object is not such a method, and the side_effect function is not bound, so self is indeed not going to be passed in. Mock对象不是这样的方法,并且side_effect函数没有绑定,因此self确实不会被传入。

If you must have access the instance in a side_effect object, you'll have to patch the function on the class with an actual function: 如果必须访问side_effect对象中的实例,则必须使用实际函数在类上修补该函数:

with patch.object(Animal, 'make_noise', new=loud):

Now make_noise is replaced by the loud function on the Animal class, so it'll be bound: 现在make_noiseAnimal类上的loud函数取代,所以它将被绑定:

>>> with patch.object(Animal, 'make_noise', new=loud):
...     dog.make_noise()
...
'WOOF!!'

The alternative is to set autospec=True , at which point mock will use a real function to mock out make_noise() : 另一种方法是设置autospec=True ,此时mock将使用实际函数来模拟make_noise()

>>> with patch.object(Animal, 'make_noise', autospec=True, side_effect=loud):
...     dog.make_noise()
...
'WOOF!!'

Also see the Mocking Unbound Methods section in the mock getting started section. 另请参阅模拟入门 部分中的Mocking Unbound Methods部分。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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