以下内容对于 Python 2 或者 Python 3 均适用。术语 mock 对象 表示用于替换代码中实际对象的 mock.Mock 或者 mock.MagicMock 对象

mock 库是 Python 中用来进行单元测试模拟的一个库。mock.call 是 mock 库中用来表示 mock 对象调用的一个辅助对象,通常我们使用一个 mock.call 对象或者一个含有多个 mock.call 对象的列表来表示我们期望发生在 mock 对象上的调用,这样不仅可以判断一个 mock 对象是否执行了期望的调用,还确认这些调用是按照期望的顺序执行的。在测试代码中,我们会将所期望的调用和 mock 对象的 call_args, call_args_list, mock_calls 以及 method_calls 这些记录内容做比较。

有一点需要注意,mock.call 本身就是一个 mock._Call 类的实例,所以它本身,即不加调用符号 (mock.call() 或者 mock.call(*args, **kwargs)) 时,表示的是 mock 对象本身

下面来看个个例子。假设 app.util.SSH 是我们封装的一个用于管理 SSH 连接,并且提供某些命令封装的类。现在 SSH 提供了两个实例方法 hostname()restart_service(service)。我们一般会这么 mock 它:

with mock.patch("app.util.SSH") as m:
    mocked_conn = mock.Mock()
    m.return_value = mocked_conn

    # test logics

    # do assert with mocked_conn object

这样,我们就可以让代码中对一个 SSH 实例的调用,转换成对我们的 mock 对象 mocked_conn 的调用。这样,代码中对 mock 对象的使用和 mock.call 的对应关系如下:

def foo(ip):
    conn = app.util.SSH(ip)          # conn == mock.call
    conn.hostname()                  # mock.call.hostname()
    conn.restart_service(service1)   # mock.call.restart_service(service1)
    conn.restart_service(service2)   # mock.call.restart_service(service2)

所以 mocked_conn.mock_calls 的内容就是

[mock.call.hostname, mock.call.restart_service(service1), mock.call.restart_service(service2)]

要进行 assert 时,你需要提供上面这个 call list。


知识共享许可协议本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。