【问题标题】:python mock.mock_calls does not follow calls made inside @timeout decorated functionpython mock.mock_calls 不遵循@timeout 装饰函数内部的调用
【发布时间】:2018-05-08 21:18:15
【问题描述】:

我正在使用 mock 对函数进行单元测试,并尝试测试是否调用了 mock 对象。在下面的代码中,requests.post 对象被模拟,我跟踪requests.post.mock_calls 列表。

在下面的代码中

代码构造:

import timeout_decorator

def block_funds(trader_id, amounts):

    @timeout_decorator.timeout(3, use_signals=False)
    def _block_funds(block_url, amounts):

        # requests.post.mock_calls empty here
        result = requests.post(url=block_url, data=amounts)
        # requests.post.mock_calls here has correct call recorded

        return result.status_code

    block_url = 'http:/someurl/somepath/{trader_id}'.format(trader_id=trader_id)

    try:

        # requests.post.mock_calls empty here
        code = _block_funds(block_url, amounts)
        # requests.post.mock_calls empty again here

    except timeout_decorator.TimeoutError as ex:
        logger.error('request failed')
        code = 500

    return code

在调用code = _block_funds(block_url, amounts) 之后,我希望模拟对象记录对它的所有调用,但是一旦执行退出内部超时包装函数_block_funds()mock_calls 列表就会被清空。 Mock 对象当然是一样的,我会按照 mock 的 ID 来确保对象没有改变。

我做错了什么以及如何让模拟不会忘记它的调用?

【问题讨论】:

  • 您在测试中用于比较的模拟对象和您在函数中测试值的模拟对象可能不是同一个对象。在您的问题中包含您的测试功能。
  • 其实我找到了原因——它是@timeout 装饰器。不,对象是相同的,我正在关注模拟对象 ID,但我发现只要我注释掉超时装饰器 - 调用就会出现并且测试通过。我现在必须弄清楚如何为测试解决这个问题。

标签: python unit-testing mocking


【解决方案1】:

我发现了问题,它在超时装饰器中,特别是在它的use_signals=False 部分。根据timeout decorator documentation,要在我的场景(多线程 Web 应用程序)中正确使用超时,您不需要使用信号而是依赖多处理,在这种情况下,我看到了这个导致问题的意外模拟。如果我删除 use_signals=False 或完全删除装饰器 - 它工作正常。

我现在的解决方案是模拟装饰器本身并避免这个问题。

更正

直接嘲笑装饰器被证明是不切实际的。相反,我将它包裹起来并模拟了包裹:

def timeout_post(**kwargs):
    @timeout_decorator.timeout(3, use_signals=False)
    def _post(**kwargs):
        return requests.post(**kwargs)

    return _post(**kwargs)

【讨论】:

    猜你喜欢
    • 2017-08-01
    • 1970-01-01
    • 2017-01-15
    • 2010-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-11
    • 2020-06-16
    相关资源
    最近更新 更多