Python mock.patch装饰器影响同一测试套件中的其他单元测试

F F*_*F F 5 python patch mocking python-decorators python-unittest

我为main_function编写了一个单元测试,并断言它使用类的实例调用其中的函数get_things,并使用patch作为参数进行模拟:

@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)
Run Code Online (Sandbox Code Playgroud)

这是主要功能:

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)
Run Code Online (Sandbox Code Playgroud)

它单独传递,但是当与其他修补MyClass.get_things()的测试一起运行时,它会失败.这是消息:

Unhandled exception occurred::'NoneType' object has no attribute 'client'
Run Code Online (Sandbox Code Playgroud)

似乎修补程序装饰器相互影响.

我试图在测试函数中创建模拟作为变量而不是装饰器,但问题仍然存在.我也尝试创建一个tearDown()来停止补丁,但它似乎不起作用.

在模拟类实例时,有没有办法隔离补丁或成功丢弃它们?

vel*_*sta 1

在这种情况下,稍微改变一下可能更适合您,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)
Run Code Online (Sandbox Code Playgroud)

或者,如果您不想更改实际的 API main_function,您可以创建一个更可测试的辅助函数并使用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)
Run Code Online (Sandbox Code Playgroud)

诚然,这些都需要对您的主函数进行代码更改,因此它们可能无法实现或特别适合您的用例。

通过将类实例作为参数而不是修补的内容,您将能够直接注入模拟对象,而无需修补类构造函数。如果没有完整的示例,很难说具体出了什么问题,但我有预感,修补构造函数会干扰其他测试