我为main_function编写了一个单元测试,并断言它使用类的实例调用函数get_things其中,并以补丁作为参数进行模拟:
@patch("get_something")
@patch("MyClass.__new__")
def test(self, mock_my_class_instance, mock_get_something):
# Given
dummy_my_class_instance = MagicMock()
mock_my_class_instance.return_value = dummy_my_class_instance
dummy_my_class_instance.get_things.return_value = {}
# When
main_function(parameter)
# Then
dummy_my_class_instance.get_things.assert_called_once_with(parameter["key1"], parameter["key2"])
mock_get_something.assert_called_once_with(dummy_my_class_instance)
这是主要功能:
def main_function(parameter):
properties = get_properties(parameter)
my_class_instance = MyClass()
list_of_things = my_class_instance.get_things(properties["key-1"], properties["key-2"])
an_object = get_something(my_class_instance)
return other_function(list_of_things, an_object)
它单独通过,但当与其他修补 MyClass.get_things(( 的测试一起运行时,它会失败。这是消息:
Unhandled exception occurred::'NoneType' object has no attribute 'client'
似乎补丁装饰器正在相互影响。
我试图将测试函数内的模拟创建为变量而不是装饰器,但问题仍然存在。我还尝试创建一个 tearDown(( 来停止补丁,但它似乎不起作用。
有没有办法在模拟类实例时隔离补丁或成功丢弃它们?
在这种情况下,稍微更改main_function
可能更适合您,以便它更易于测试。您至少可以通过两种方式执行此操作:
您可以像这样为my_class_instance
添加一个可选参数:
def main_function(parameter, my_instance = None):
properties = get_properties(parameter)
my_class_instance = my_instance if my_instance is not None else MyClass()
list_of_things = my_class_instance.get_things(properties["key-1"], properties["key-2"])
an_object = get_something(my_class_instance)
return other_function(list_of_things, an_object)
或者,如果您不想更改实际main_function
的 API,则可以创建一个更易于测试的帮助程序函数,并将main_function
用作传递:
def _testable_main_function(parameter, my_instance = None):
properties = get_properties(parameter)
my_class_instance = my_instance if my_instance is not None else MyClass()
list_of_things = my_class_instance.get_things(properties["key-1"], properties["key-2"])
an_object = get_something(my_class_instance)
return other_function(list_of_things, an_object)
def main_function(parameters):
return _testable_main_function(parameters)
诚然,这些都需要对主函数进行代码更改,因此它们可能无法实现或特别适合您的用例。
由于类实例是一个参数而不是修补的东西,您将能够直接注入模拟对象,而无需修补类构造函数。如果没有一个完整的示例可以玩,很难说这是具体出错的地方,但我有一种预感,修补构造函数会干扰其他测试