自定义pytest中特定异常的错误消息 [英] Customizing error message for specific exceptions in pytest

查看:94
本文介绍了自定义pytest中特定异常的错误消息的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写一个 pytest 插件来自定义特定异常的外观 - 更具体地说,模拟异常(预期被调用的方法未被调用等),因为在这些异常的回溯中有很多无用的噪音例外.

I'm trying to write a pytest plugin to customize the appearance of specific exceptions - more specifically, mocking exceptions (method expected to be called was not called etc.), because there's a lot of useless noise in the traceback of those exceptions.

这是我到目前为止所得到的,它有效,但非常笨拙:

This is what I've got so far, which works, but is extremely hacky:

import pytest
import flexmock

@pytest.hookimpl()
def pytest_exception_interact(node, call, report):
    exc_type = call.excinfo.type

    if exc_type == flexmock.MethodCallError:
        entry = report.longrepr.reprtraceback.reprentries[-1]
        entry.style = 'short'
        entry.lines = [entry.lines[-1]]
        report.longrepr.reprtraceback.reprentries = [entry]

我认为我使用 hookimpl 做正确的事情并使用简单的 if 语句检查异常类型.

I think I'm doing the right thing with the hookimpl and checking the exception type with a simple if statement.

我尝试用一​​个简单的字符串替换 report.longrepr ,这也有效,但后来我失去了格式(终端中的颜色).

I tried replaceing report.longrepr with a simple string, which also worked, but then I lose out on formatting (colors in the terminal).

作为我想要缩短的输出类型的示例,这是一个模拟断言失败:

As an example of the type of output I want to shorten, here's a mock assertion failure:

=================================== FAILURES ====================================
_______________________ test_session_calls_remote_client ________________________

    def test_session_calls_remote_client():
        remote_client = mock.Mock()
        session = _make_session(remote_client)
        session.connect()
        remote_client.connect.assert_called_once_with()
        session.run_action('asdf')
>       remote_client.run_action.assert_called_once_with('asdff')

tests/unit/executor/remote_test.py:22: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/opt/python-3.6.3/lib/python3.6/unittest/mock.py:825: in assert_called_once_with
    return self.assert_called_with(*args, **kwargs)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

_mock_self = <Mock name='mock.run_action' id='139987553103944'>
args = ('asdff',), kwargs = {}, expected = (('asdff',), {})
_error_message = <function NonCallableMock.assert_called_with.<locals>._error_message at 0x7f51646269d8>
actual = call('asdf'), cause = None

    def assert_called_with(_mock_self, *args, **kwargs):
        """assert that the mock was called with the specified arguments.

            Raises an AssertionError if the args and keyword args passed in are
            different to the last call to the mock."""
        self = _mock_self
        if self.call_args is None:
            expected = self._format_mock_call_signature(args, kwargs)
            raise AssertionError('Expected call: %s\nNot called' % (expected,))

        def _error_message():
            msg = self._format_mock_failure_message(args, kwargs)
            return msg
        expected = self._call_matcher((args, kwargs))
        actual = self._call_matcher(self.call_args)
        if expected != actual:
            cause = expected if isinstance(expected, Exception) else None
>           raise AssertionError(_error_message()) from cause
E           AssertionError: Expected call: run_action('asdff')
E           Actual call: run_action('asdf')

/opt/python-3.6.3/lib/python3.6/unittest/mock.py:814: AssertionError
====================== 1 failed, 30 passed in 0.28 seconds ======================

推荐答案

如果您的目标是使堆栈跟踪更易于阅读,那么您可以使用以下代码块输出自定义错误消息.此自定义错误消息出现在堆栈跟踪的末尾,因此您无需向上滚动:

If your goal is to make the stacktrace easier to read, then you can use the below code block to output a custom error message. This custom error message appears at end of the stacktrace, so you don't need to scroll up:

with raises(ZeroDivisionError, message="Expecting ZeroDivisionError"):
    pass
--> Failed: Expecting ZeroDivisionError

来源:pytest 的文档.因此,您可以通过诸如 grep 之类的东西来传输 pytest 的输出,并过滤掉堆栈跟踪中无用的部分,而不是制作插件.

Source: pytest's documentation. So, instead of making a plugin you can pipe the output of pytest through something like grep and filter out the useless parts of the stacktrace.

根据我在文档中读到的内容,您使用了正确的 pytest 装饰器和钩子函数 (pytest_exception_interact).但是,可能不需要对错误进行类型检查.文档的这一部分说这个钩子仅在引发了不是内部异常(如 skip.Exception)的异常时才调用."

Based on what I read in the documentation you're using the correct pytest decorator and hook function(pytest_exception_interact). But, type checking for the error might be unnecessary. This section of the documentation says that "This hook is only called if an exception was raised that is not an internal exception like skip.Exception."

这篇关于自定义pytest中特定异常的错误消息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆