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

ⅰ亾dé卋堺 提交于 2021-02-06 09:42:05

问题


I am using Pycharm to run my pytest unit tests. I am testing a REST API, so I often have to validate blocks of JSON. When a test fails, I'll see something like this:

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>

When I click on the "Click to see difference" link, most of the difference is converted to points of ellipses, like so

This is useless since it doesn't show me what is different. I get this behavior for any difference larger than a single string or number.

I assume Pycharm and/or pytest tries to elide uninformative parts of differences for large outputs. However, it's being too aggressive here and eliding everything.

How do I get Pycharm and/or pytest to show me the entire difference?

I've tried adding -vvv to pytest's Additional Arguments, but that has no effect.


Since the original post I verified that I see the same behavior when I run unit tests from the command line. So this is an issue with pytest and not Pycharm.

After looking at the answers I've got so far I guess what I'm really asking is "in pytest is it possible to set maxDiff=None without changing the source code of your tests?" The impression I've gotten from reading about pytest is that the -vv switch is what controls this setting, but this does not appear to be the case.


回答1:


If you look closely into PyCharm sources, from the whole pytest output, PyCharm uses a single line the to parse the data for displaying in the Click to see difference dialog. This is the AssertionError: <message> line:

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

If you want to see the full diff line without truncation, you need to customize this line in the output. For a single test, this can be done by adding a custom message to the assert statement:

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

If you want to apply this behaviour to all tests, define custom pytest_assertrepr_compare hook. In the conftest.py file:

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

The equality comparison of the values will now still be stripped when too long; to show the complete line, you still need to increase the verbosity with -vv flag.

Now the equality comparison of the values in the AssertionError line will not be stripped and the full diff is displayed in the Click to see difference dialog, highlighting the diff parts:




回答2:


Being that pytest integrates with unittest, as a workaround you may be able to set it up as a unittest and then set Test.maxDiff = None or per each specific test self.maxDiff = None

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

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

These may be helpful as well...

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

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




回答3:


Had a look in the pytest code base and maybe you can try some of these out:

1) Set verbosity level in the test execution:

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

2) Add environment variable for "CI" or "BUILD_NUMBER". In the link to the truncate file you can see that these env variables are used to determine whether or not the truncation block is run.

import os

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

3) Attempt to set DEFAULT_MAX_LINES and DEFAULT_MAX_CHARS on the truncate module (Not recommending this since it uses a private module):

from _pytest.assertion import truncate

truncate.DEFAULT_MAX_CHARS = 1000
truncate.DEFAULT_MAX_LINES = 1000

According to the code the -vv option should work so it's strange that it's not for you:

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

Pytest truncation file which are what I'm basing my answers off of: pytest/truncate.py

Hope something here helps you!




回答4:


I was running into something similar and created a function that returns a string with a nice diff of the two dicts. In pytest style test this looks like:

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

And in unittest style

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

The downside is that you have to modify the all the tests that have this issue, but it's a Keep It Simple and Stupid solution.




回答5:


In pycharm you can just put -vv in the run configuration Additional Arguments field and this should solve the issue.

Or at least, it worked on my machine...




回答6:


I have some getattr in assertion and it never shows anything after AssertionError.

I add -lv in the Additional Arguments field to show the local variables.



来源:https://stackoverflow.com/questions/50608443/how-do-i-get-pycharm-to-show-entire-error-diffs-from-pytest

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!