代码之家  ›  专栏  ›  技术社区  ›  W.P. McNeill

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

  •  20
  • W.P. McNeill  · 技术社区  · 7 年前

    我在用 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的附加参数,但这没有效果。


    从最初的post开始,我验证了从命令行运行单元测试时看到的行为是相同的。所以这是Pytest而不是PyCharm的问题。

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

    3 回复  |  直到 7 年前
        1
  •  15
  •   hoefling    6 年前

    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 行将不会被剥离,并且完全差异显示在 点击查看差异 对话框,突出显示差异部分:

    enter image description here

        2
  •  3
  •   shmuels    7 年前

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

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

    可以在开箱即用的情况下运行unittest(包括试用版)和nose测试套件;

    这些可能也有帮助…

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

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

        3
  •  0
  •   cullzie    6 年前

    看看pytest代码库,也许你可以尝试一下:

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

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

    2)为“ci”或“build_number”添加环境变量。链接到 您可以看到这些env变量用于 确定是否运行截断块。

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

    3)尝试设置截断模块上的默认最大行和默认最大字符( 不建议这样做,因为它使用私有模块 ):

    from _pytest.assertion import truncate
    
    truncate.DEFAULT_MAX_CHARS = 1000
    truncate.DEFAULT_MAX_LINES = 1000
    

    根据代码,-vv选项应该可以工作,所以奇怪的是它不适合您:

    当前的默认行为是在 ~8条终端线,除非在“-vv”模式下运行或在ci上运行。

    pytest截断文件,这是我的答案的基础: pytest/truncate.py

    希望这里有帮助!