重用 Mock 创建属性模拟 unittest.patch

Reusing Mock to create attribute mocks unittest.patch

from unittest.mock import patch


class A:
    def b(self):
        return 'HAHAHA A'
a = A()

with patch('__main__.A') as a_mock:
    a_mock.b.return_value = 'not working'
    print(a.b())

HAHAHA A
>>>

为什么不打印 'not working'?那么 a_mock 是干什么用的呢? ______________

您用补丁替换了 整个 class,而不是现有 class 上的方法。 a = A() 在替换 class 之前创建了 A 的实例,因此 a.__class__ 仍然引用实际的 class,而不是模拟。

Mocking 一次只能替换一个引用,而不能替换引用的对象。在补丁之前,名称 A 和属性 a.__class__ 都是对 class 对象的引用。然后,您只修补了 A 引用,将 a.__class__ 留在原地。

换句话说,a.__class__没有打补丁,只有AA().b() 打印not working

您必须修补只是 class 上的方法,这样a.__class__ 仍然引用A,并且a.b 将解析为修补后的 A.b mock:

with patch('__main__.A.b') as b_mock:
    b_mock.return_value = 'working as long as you patch the right object'
    print(a.b())

演示:

>>> with patch('__main__.A.b') as b_mock:
...     b_mock.return_value = 'working as long as you patch the right object'
...     print(a.b())
...
working as long as you patch the right object

不幸的是,您不能用 Mock 修补 a.__class__ 引用; Python 只允许您对该属性使用实际的 classes。

>>> with patch('__main__.a.__class__') as a_class_mock:
...     a_class_mock.b.return_value = 'working as long as you patch the right object'
...     print(a.b())
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/mjpieters/Development/Library/buildout.python/parts/opt/lib/python3.5/unittest/mock.py", line 1312, in __enter__
    setattr(self.target, self.attribute, new_attr)
TypeError: __class__ must be set to a class, not 'MagicMock' object

您可能想要修补您的实例而不是您的 class:

with patch('__main__.a') as a_mock:
    a_mock.b.return_value = 'works perfectly ;)'
    print(a.b())