如何模拟/测试记录器报告异常?

时间:2019-03-26 17:20:15

标签: python logging mocking

请问任何人都不能解释为什么以下assert_called_with不起作用吗?

根据pytest的“预期调用”打印的信息等于“实际调用”,因此我假设pytest将其转换为str并在终端上打印时会丢失一些信息。

您建议使用哪种工具进行调试?

程序:

import logging
from mock import patch

logger = logging.getLogger(__name__)
logger.addHandler(logging.StreamHandler())

def func():
    try:
        raise ValueError("error XYZ")
    except ValueError as err:
        logger.error(err)

def test_func():
    with patch('logging.Logger.error') as log:
        func()
        log.assert_called_with(ValueError("error XYZ"))

执行:

$ pytest prog.py
=========================================================================== test session starts ===========================================================================
platform linux2 -- Python 2.7.15+, pytest-4.2.0, py-1.7.0, pluggy-0.8.1
rootdir: /tmp, inifile:
collected 1 item

prog.py F                                                                                                                                                           [100%]

================================================================================ FAILURES =================================================================================
________________________________________________________________________________ test_func ________________________________________________________________________________

    def test_func():
        with patch('logging.Logger.error') as log:
            func()
>           log.assert_called_with(ValueError("error XYZ"))

prog.py:16:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/home/ebajgrz/py27/local/lib/python2.7/site-packages/mock/mock.py:937: in assert_called_with
    six.raise_from(AssertionError(_error_message(cause)), cause)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

value = AssertionError("Expected call: error(ValueError('error XYZ',))\nActual call: error(ValueError('error XYZ',))",), from_value = None

    def raise_from(value, from_value):
>       raise value
E       AssertionError: Expected call: error(ValueError('error XYZ',))
E       Actual call: error(ValueError('error XYZ',))

/home/ebajgrz/py27/local/lib/python2.7/site-packages/six.py:737: AssertionError
======================================================================== deprecated python version ========================================================================
You are using Python 2.7.15, which will no longer be supported in pytest 5.0
For more information, please read:
  https://docs.pytest.org/en/latest/py27-py34-deprecation.html
======================================================================== 1 failed in 0.28 seconds ============================

我意识到pytest具有功能日志,可以按以下方式执行测试,但是我想了解为什么第一种方法不起作用。

def test_func2(caplog):
    func()
    assert 'error XYZ' in caplog.text

1 个答案:

答案 0 :(得分:1)

这是因为limit正在根据预期对象检查传入的对象。它们是不同的对象,因此断言失败。例如,打开python shell并尝试以下操作:

mock

它们不相等,因为它们是不同的对象。但是尝试一下:

>>> ValueError('bees') == ValueError('bees')
False

这是因为字符串是不可变的。现在,如果您将原始日志调用更改为>>> str(ValueError('bees')) == str(ValueError('bees')) True ,并将断言更改为logger.error(str(err)),那么我认为您将克服第一个错误。

与此无关,还有更多关于记录异常的建议:您可能希望像这样在except块中记录更多信息。像这样:

log.assert_called_with(str(ValueError("error XYZ")))