如何让 PyCharm 显示来自 pytest 的整个错误差异?

How do I get PyCharm to show entire error diffs from pytest?

我正在使用 Pycharm to run my pytest 单元测试。我正在测试 REST API,因此我经常需要验证 JSON 的块。当测试失败时,我会看到类似这样的内容:

FAILED
test_document_api.py:0 (test_create_documents)
{'items': [{'i...ages': 1, ...} != {'items': [{'...ages': 1, ...}

Expected :{'items': [{'...ages': 1, ...}
Actual   :{'items': [{'i...ages': 1, ...}
 <Click to see difference>

当我点击 "Click to see difference" link 时,大部分差异被转换为椭圆点,像这样

这是无用的,因为它没有告诉我有什么不同。对于大于单个字符串或数字的任何差异,我都会得到这种行为。

我假设 Pycharm and/or pytest 试图消除大输出差异中无信息的部分。但是,它在这里过于激进并且省略了所有内容。

如何让 Pycharm and/or pytest 显示全部差异?

我试过将 -vvv 添加到 pytest 的附加参数中,但这没有效果。


自从最初的 post 我验证了当我从命令行进行 运行 单元测试时我看到了相同的行为。所以这是 pytest 的问题,而不是 Pycharm.

看了到目前为止我得到的答案后,我想我真正想问的是 "in pytest is it possible to set maxDiff=None without changing the source code of your tests?" 我从阅读有关 pytest 的文章中得到的印象是 -vv 开关是是什么控制了这个设置,但情况似乎并非如此。

由于 pytest 与 unittest 集成,作为一种解决方法,您可以将其设置为 unittest,然后设置 Test.maxDiff = None 或每个特定测试 self.maxDiff = None

https://docs.pytest.org/en/latest/index.html

Can run unittest (including trial) and nose test suites out of the box;

这些也可能有帮助...

If you look closely into PyCharm sources,从整个 pytest 输出中,PyCharm 使用单行解析数据以显示在 Click to see difference 对话框中。这是 AssertionError: <message> 行:

def test_spam():
>       assert v1 == v2
<b>E       AssertionError: assert {'foo': 'bar'} == {'foo': 'baz'}</b>
E         Differing items:
E         {'foo': 'bar'} != {'foo': 'baz'}
E         Use -v to get the full diff

如果你想看到没有截断的完整差异行,你需要在输出中自定义这一行。对于单个测试,这可以通过将自定义消息添加到 assert 语句来完成:

def test_eggs():
    assert a == b, '{0} != {1}'.format(a, b)

如果要将此行为应用于所有测试,请定义自定义 pytest_assertrepr_compare 挂钩。在 conftest.py 文件中:

# conftest.py
def pytest_assertrepr_compare(config, op, left, right):
    if op in ('==', '!='):
        return ['{0} {1} {2}'.format(left, op, right)]

值的相等比较现在仍然会在太长时被剥离;要显示完整的行,您仍然需要使用 -vv 标志来增加详细程度。

现在 AssertionError 行中的值的相等比较将不会被删除,完整的差异显示在 Click to see difference 对话框中,突出显示差异部分:

查看了 pytest 代码库,也许您可​​以尝试其中的一些:

1) 在测试执行中设置详细级别:

./app_main --pytest --verbose test-suite/

2) 为"CI" 或"BUILD_NUMBER" 添加环境变量。在 link 到 t运行cate 文件你可以看到这些环境变量是用来 判断 t运行cation 块是否为 运行.

import os

os.environ["BUILD_NUMBER"] = '1'
os.environ["CI"] = 'CI_BUILD'

3) 尝试在 t运行cate 模块上设置 DEFAULT_MAX_LINES 和 DEFAULT_MAX_CHARS(不推荐这样做,因为它使用私有模块):

from _pytest.assertion import truncate

truncate.DEFAULT_MAX_CHARS = 1000
truncate.DEFAULT_MAX_LINES = 1000

根据代码,-vv 选项应该有效,所以很奇怪它不适合你:

Current default behaviour is to truncate assertion explanations at ~8 terminal lines, unless running in "-vv" mode or running on CI.

Pytest t运行cation 文件,我的答案基于:pytest/truncate.py

希望这里的内容对您有所帮助!

我 运行 陷入了类似的境地,并创建了一个函数,该函数 returns 一个字符串,其中两个 dicts 具有很好的差异。在 pytest 样式测试中,它看起来像:

assert expected == actual, build_diff_string(expected, actual)

并采用 unittest 风格

self.assertEqual(expected, actual, build_diff_string(expected, actual)

缺点是你必须修改所有有这个问题的测试,但这是一个保持简单和愚蠢的解决方案。

在 pycharm 中,您可以将 -vv 放在 运行 配置的附加参数字段中,这应该可以解决问题。

或者至少,它在我的机器上运行...

我在断言中有一些 getattr,但在 AssertionError 之后它不再显示任何内容。

我在 Additional Arguments 字段中添加 -lv 以显示局部变量。