Python 单元测试 - 模拟与补丁

Python Unittest - Mock vs Patch

  1. 使用 mock.Mock()mock.patch() 有什么区别?

  2. 何时使用mock.Mock()以及何时使用mock.patch()

  3. 我读过 Mock 用于替换当前作用域中使用的内容,而 patch 用于替换导入的内容 and/or 在另一个作用域中创建的内容。谁能解释一下这是什么意思?

我不确定我是否理解你的问题,但我会试一试。 如 documentation 中所述,Mock 对象(实际上是 MagickMock 个实例)是使用 patch 装饰器创建的:

from unittest.mock import patch

@patch('some_module.some_object')
def test_something(mocked_object):
    print(mocked_object)

这给出了类似的东西:

<MagicMock name='some_object' id='1870192381512'>

这等同于:

def test_something():
    with patch('some_module.some_object') as mocked_object:
        print(mocked_object)

这使您可以用模拟对象替换任何对象,以避免调用实际生产代码 and/or 来检查原始对象的调用方式(如果对象是函数)。首选使用 patch (或一些类似方法)的原因是,这确保补丁在测试后(或在第二种情况下的上下文管理器范围之后)恢复,因此对其他没有副作用测试或其他代码。

引用文档:

The patch decorators are used for patching objects only within the scope of the function they decorate. They automatically handle the unpatching for you, even if exceptions are raised. All of these functions can also be used in with statements or as class decorators.

您还可以手动创建一个 Mock 对象并将其分配给一个对象——我想这就是您在问题中的意思。如果您这样做而不是使用 patch,您有责任自行重置之前的状态。由于这更多error-prone,如果可能的话,我会建议使用专门的补丁方法。

这无关紧要的地方是在本地对象和其他模拟中。很少需要模拟本地对象,但 Mock 实例通常与修补对象一起创建,以保留模拟对象的实例以供以后检查:

@mock.patch('my_functions.MyClass')
def test_object(mock_class):
    arg1 = Mock()
    arg2 = Mock()
    do_something(arg1, arg2)

    # check that do_something creates MyClass with the given arguments 
    mock_class.assert_called_with(arg1, arg2)

在这种情况下,case 将仅用作模拟对象的参数,因此不需要重置。

总结一下:

  • patch 是一个方便的 decorator/context 管理器函数,用于用模拟对象(或其他对象)替换对象并在完成后或发生异常时重置先前的状态
  • Mock或派生对象由mock.patch创建,也可以手动创建。手动创建的模拟通常只用于修补本地函数或其他不需要重置的模拟。