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

时间:2018-05-30 15:28:01

标签: python pycharm pytest difference

我正在使用Pycharm来运行我的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>

当我点击“点击查看差异”链接时,大部分差异将转换为省略点,如此

Pycharm comparison with differences elided

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

我假设Pycharm和/或pytest试图消除大输出差异的无信息部分。然而,它在这里过于激进并且一切都在消失。

如何让Pycharm和/或pytest向我展示完整的差异?

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

从原始帖子开始,我验证了当我从命令行运行单元测试时,我看到了相同的行为。所以这是pytest而不是Pycharm的问题。

在查看到目前为止我得到的答案之后,我想我真正要问的是“在pytest中是否可以在不更改测试源代码的情况下设置maxDiff=None?”我从阅读有关pytest的印象是,-vv开关是控制此设置的,但事实并非如此。

6 个答案:

答案 0 :(得分:11)

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

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

如果要查看完整的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对话框中会显示完整的差异,突出显示差异部分:

enter image description here

答案 1 :(得分:3)

由于pytest与unittest集成,因此您可以将其设置为单元测试,然后设置Test.maxDiff = None或每个特定测试self.maxDiff = None

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

  

可以开箱即用单元测试(包括试用)和鼻子测试套件;

这些也可能有用......

https://stackoverflow.com/a/21615720/9530790

https://stackoverflow.com/a/23617918/9530790

答案 2 :(得分:0)

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

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

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

2)为“ CI”或“ BUILD_NUMBER”添加环境变量。在链接到    截断文件,您可以看到这些环境变量用于    确定是否运行了截断块。

import os

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

3)尝试在截断模块上设置DEFAULT_MAX_LINES和DEFAULT_MAX_CHARS(不建议这样做,因为它使用私有模块):

from _pytest.assertion import truncate

truncate.DEFAULT_MAX_CHARS = 1000
truncate.DEFAULT_MAX_LINES = 1000

根据代码,-vv选项应该可以正常工作,因此很奇怪它不适合您:

  

当前的默认行为是在以下位置截断断言说明   大约8条终端线,除非以“ -vv”模式运行或在CI上运行。

Pytest截断文件是我基于以下原因得出的答案:pytest/truncate.py

希望这里有所帮助!

答案 3 :(得分:0)

我遇到了类似的情况,并创建了一个函数,该函数返回一个字符串,其中两个dicts的差值很好。在pytest样式测试中,它看起来像:

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

并以unittest风格

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

缺点是您必须修改所有存在此问题的测试,但这是一个“保持简单而愚蠢”的解决方案。

答案 4 :(得分:0)

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

或者至少可以在我的机器上工作...

答案 5 :(得分:0)

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

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