【问题标题】:Spying on class instantiation and methods监视类实例化和方法
【发布时间】:2018-05-19 16:36:29
【问题描述】:

我希望能够看到类是如何实例化的,并且我希望看到该类的方法是如何被使用的。我可以实现第一个目标,但是,下面的代码演示了我如何无法监视方法调用。最终断言失败。

import mock

class A:
    def __init__(self, some_arg):
        print("constructor")

    def f(self, some_var):
        print(some_var)

p = mock.patch('__main__.A', wraps=A)
m = p.start()
A = m
a = A('something')
a.f('my_arg')
assert mock.call('something') in m.mock_calls
assert m.method_calls  # This fails, call to f is not tracked

如果我使用 autospec=True,我可以看到方法调用,但不会调用实际方法。我想让实际的代码运行,我只是想监视它。

我不能做像http://wesmckinney.com/blog/spying-with-python-mocks/ 这样的事情,因为我没有该类的实例。

【问题讨论】:

  • 不相关,但不需要A = m;补丁已经导致 A 引用模拟,而不是原始类。
  • 我不确定是否有一种简单的方法可以实现这一点。 wrap 仅处理对函数(或其他可调用函数)的调用。对模拟的A调用 会导致对真实A 的调用,但返回值根本不是模拟;它是原始类的常规实例。

标签: python python-2.7 unit-testing mocking


【解决方案1】:

这个https://stackoverflow.com/a/41599695/9816369 有一个非常可靠的解决方案。由此,我可以这样做:

import mock


def spy_decorator(method_to_decorate):
    m = mock.MagicMock()
    def wrapper(self, *args, **kwargs):
        m(*args, **kwargs)
        return method_to_decorate(self, *args, **kwargs)
    wrapper.mock = m
    return wrapper


class A:
    def __init__(self, some_arg):
        print("constructor")

    def f(self, some_var):
        print(some_var)


construct_spy = spy_decorator(A.__init__)
f_spy = spy_decorator(A.f)
p_construct = mock.patch('__main__.A.__init__', construct_spy)
p_f = mock.patch('__main__.A.f', f_spy)

m_construct = p_construct.start()
m_f = p_f.start()

a = A("hi")
a.f("car")

m_construct.mock.assert_called_once_with("hi")
m_f.mock.assert_called_once_with("car")

它可能会更好一些,但这非常可靠。我还应该提到有https://github.com/beanbaginc/kgb,但我不想修改我正在使用的需求文件。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-09-27
    • 1970-01-01
    • 2016-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-11
    相关资源
    最近更新 更多