使用 Python Mock 库监视内部方法调用

Posted

技术标签:

【中文标题】使用 Python Mock 库监视内部方法调用【英文标题】:Using Python Mock library to spy on internal method calls 【发布时间】:2014-01-06 14:35:40 【问题描述】:

我正在使用 Python 模拟模块进行测试。我想监视由活动对象进行的内部方法调用。我发现 'wraps' kwarg 可用于设置一个模拟来监视对活动对象的方法调用:

Using Python mock to spy on calls to an existing object

但这不适用于内部呼叫。我想用它来测试更高级别的方法是否以正确的顺序调用更低级别的方法。

给定:

class ClassUnderTest(object):
    def lower_1(self):
        print 'lower_1'

    def lower_2(self):
        print 'lower_2'

    def higher(self):
        self.lower_1()
        self.lower_2()

我希望能够测试它

import mock

DUT = ClassUnderTest()
mock_DUT = mock.Mock(wraps=DUT)
# test call
mock_DUT.higher()

# Assert that lower_1 was called before lower_2
assert mock_DUT.mock_calls[1:] = [mock.call.lower_1(), mock.call.lower_2()]

这不起作用,因为 'self' 参数 high() 绑定到原始 DUT 对象,而不是 mock_DUT 间谍。因此,只有初始的 Higher() 调用会记录到 mock_calls。有没有一种方便的方法来使用 python 模拟模块执行这种断言?

【问题讨论】:

【参考方案1】:

这有点像在 Java 中使用 Mockito 间谍。 http://docs.mockito.googlecode.com/hg/latest/org/mockito/Spy.html

您可以使用 Mock(spec=obj) 构造函数构造一个“间谍”,这将使 __class__ 属性等于 ClassUnderTest,而 Mock(wraps=obj) 构造函数则不会。由于在 python 中的类方法采用类实例,即 self 参数作为它们的第一个参数,因此您可以使用 mock 调用它,就好像它是类上的静态方法一样。

import mock

DUT = ClassUnderTest()
spy = mock.Mock(spec=DUT)
# test call
ClassUnderTest.higher(spy)

# Assert that lower_1 was called before lower_2
assert spy.mock_calls == [mock.call.lower_1(), mock.call.lower_2()]

【讨论】:

以上是关于使用 Python Mock 库监视内部方法调用的主要内容,如果未能解决你的问题,请参考以下文章

Python 3 unittest不能在函数内部使用mock方法

Mockito-部分mock测试使用

具有多次调用方法的 Python Mock 对象

Python mock 修补另一个函数调用的函数

JAVA方法mock调用工具的实现

Jest 使用指南 - - Mock 篇