在测试中,我们可能需要对同一个模块进行两次模拟,例如,同一个模块被两个不同的类所导入,我们需要分别对这两个类中的模块进行模拟。但是,如果我们直接对模块进行模拟,那么两个类中模拟的模块都会变成同一个对象,这会导致测试结果不正确。
2. 解决方案
为了解决这个问题,我们可以使用 Mock 库中的 patch.object() 函数。patch.object() 函数可以对一个对象的属性进行模拟,而不会影响其他对象的属性。因此,我们可以分别对两个类中的模块进行模拟,而不会影响其他类的模块。
# file test_sub_class.py:
from unittest import TestCase
from mock import Mock, patch
import sub_class
import base_class
MOCK_OBJECT = Mock()
class TestSubClass(TestCase):
@patch.object(sub_class, 'module_to_patch', MOCK_OBJECT)
@patch.object(base_class, 'module_to_patch', MOCK_OBJECT)
def test_sub_class_init(self):
self.base_class = base_class.base_class()
self.assertTrue(MOCK_OBJECT.foo.called)
self.sub_class = sub_class.sub_class()
self.assertTrue(MOCK_OBJECT.faa.called)
在上面的代码中,我们首先创建了一个 Mock 对象 MOCK_OBJECT,然后使用 patch.object() 函数分别对 sub_class 和 base_class 中的 module_to_patch 属性进行了模拟,并将 MOCK_OBJECT 作为模拟的对象。这样,我们就可以分别对这两个类中的模块进行模拟,而不会影响其他类的模块。
问题
- 是否有更简单的方法来实现此功能?
- 如果没有,两个补丁都修补了同一个实体,我该怎么做才能让两个补丁程序返回相同的
Mock()对象?我只需将mock_1作为新对象传递给patcher_2吗? - 上述是否处理这种情况的正确方法?
答案
- 实现您认为自己正在尝试做的事情的最简单方法是简单地模拟您导入的对象中的模块。如果您只想在整个测试套件中模拟模块:
# file test_sub_class.py:
from unittest import TestCase
from mock import Mock
import sub_class
import base_class
MODULE_MOCK = Mock()
sub_class.module_to_patch = MODULE_MOCK
base_class.module_to_patch = MODULE_MOCK
class TestSubClass(TestCase):
def test_sub_class_init(self):
self.base_class = base_class.base_class()
self.assertTrue(MODULE_MOCK.foo.called)
self.sub_class = sub_class.sub_class()
self.assertTrue(MODULE_MOCK.faa.called)
- 如果您只想模拟一个测试,可以使用
patch.object作为装饰器并为其提供要使用patch.object的 Mock 对象 (MOCK_OBJECT):
# file test_sub_class.py:
from unittest import TestCase
from mock import Mock, patch
import sub_class
import base_class
MOCK_OBJECT = Mock()
class TestSubClass(TestCase):
@patch.object(sub_class, 'module_to_patch', MOCK_OBJECT)
@patch.object(base_class, 'module_to_patch', MOCK_OBJECT)
def test_sub_class_init(self):
self.base_class = base_class.base_class()
self.assertTrue(MOCK_OBJECT.foo.called)
self.sub_class = sub_class.sub_class()
self.assertTrue(MOCK_OBJECT.faa.called)
- 是的,这是处理这种情况的正确方法。