使用 pytest + Pycharm 的长字符串的烦人的 diff 格式

问题描述 投票:0回答:2

嗨,有这个非常基本的测试:

def test_long_diff():
    long_str1 = "ABCDEFGHIJ " * 10
    long_str2 = "ABCDEFGHIJ " * 5 + "* " + "ABCDEFGHIJ " * 5
    assert long_str1 == long_str2

使用:Python 3.8.5、pytest-6.2.1、PyCharm 2020.2、MacOs

从 shell 中使用 pytest 运行,输出是“可用的”,并且错误消息将指出长字符串中的错误字符:

(venv) ~/dev/testdiff/> pytest longdiff.py 
========== test session starts ===========
platform darwin -- Python 3.8.5, pytest-6.2.1, py-1.10.0, pluggy-0.13.1
[...]
>       assert long_str1 == long_str2
E       AssertionError: assert 'ABCDEFGHIJ A...J ABCDEFGHIJ ' == 'ABCDEFGHIJ A...J ABCDEFGHIJ '
E         Skipping 45 identical leading characters in diff, use -v to show
E         - BCDEFGHIJ * ABCDEFGHIJ ABCDEFGHIJ ABCDEFGHIJ ABCDEFGHIJ ABCDEFGHIJ 
E         ?          --
E         + BCDEFGHIJ ABCDEFGHIJ ABCDEFGHIJ ABCDEFGHIJ ABCDEFGHIJ ABCDEFGHIJ

使用 pytest-clarity 和

-vv
选项,我得到彩色差异(未渲染如下)和不同的细节:

E         left:  "ABCDEFGHIJ ABCDEFGHIJ ABCDEFGHIJ ABCDEFGHIJ ABCDEFGHIJ ABCDEFGHIJ ABCDEFGHIJ ABCDEFGHIJ ABCDEFGHIJ ABCDEFGHIJ "
E         right: "ABCDEFGHIJ ABCDEFGHIJ ABCDEFGHIJ ABCDEFGHIJ ABCDEFGHIJ * ABCDEFGHIJ ABCDEFGHIJ ABCDEFGHIJ ABCDEFGHIJ ABCDEFGHIJ "
E         
E         left and right have different lengths:
E           len(left) == 110, len(right) == 112

但是如果我让 Pycharm 运行测试(相同的 Python 版本,相同的 .venv,我只需右键单击测试并选择“运行 'pytest for ...'”),运行控制台中的输出几乎无法使用,因为“沿途的东西”在应用差异之前将长字符串转换为较短字符串的元组:

FAILED                                       [100%]
longdiff.py:0 (test_long_diff)
('ABCDEFGHIJ ABCDEFGHIJ ABCDEFGHIJ ABCDEFGHIJ ABCDEFGHIJ ABCDEFGHIJ ABCDEFGHIJ '
 'ABCDEFGHIJ ABCDEFGHIJ ABCDEFGHIJ ') != ('ABCDEFGHIJ ABCDEFGHIJ ABCDEFGHIJ ABCDEFGHIJ ABCDEFGHIJ * ABCDEFGHIJ '
 'ABCDEFGHIJ ABCDEFGHIJ ABCDEFGHIJ ABCDEFGHIJ ')

<Click to see difference>

单击

<Click to see difference>
基本上会在更大的窗口中显示相同的乱码输出

是什么导致了 Pycharm 的输出?有没有办法阻止这种行为?理想情况下,我希望在运行控制台中看到 pytest-clarity 的输出。

python pycharm pytest
2个回答
2
投票

事实证明这是 PyCharm 使用的 pytest 插件的硬编码行为。该插件始终将

pprint.pformat()
应用于左侧和右侧值。

当字符串长度超过 80 个字符且包含空格时,就会出现问题中描述的行为。

一种可能的解决方法是覆盖插件的

pytest_assertrepr_compare
挂钩。这是一个对我有用的版本。只需将其粘贴到您的
conftest.py
中即可。

import pprint
import pytest

@pytest.hookimpl(tryfirst=True)
def pytest_assertrepr_compare(config, op, left, right):
    if op in ('==', '!='):
        return ['{0} {1} {2}'.format(pprint.pformat(left, width=999), op, pprint.pformat(right, width=999))]

另一种可能将其破解为monkeypatch

pprint.pformat

import pytest
import pprint
from functools import partial

@pytest.fixture(scope='function', autouse=True)
def fix_long_string_diffs(monkeypatch):
    monkeypatch.setattr(pprint, 'pformat', partial(pprint.pformat, width=999))

0
投票

我遇到了与此处描述的相同的问题: https://youtrack.jetbrains.com/issue/PY-49505/Tests-comparison-failure-Click-to-see-the-difference-multiline-strings-are-badly-formatted-in-the-diff-view

受到@Coyotwill的启发,这段代码对我有用:

@pytest.fixture(scope="function", autouse=True)
def fix_diff_formatting_for_strings_in_pytest_assert(monkeypatch):
    original_pprint_pformat = pprint.pformat

    def new_pprint_pformat(obj, *args, **kwargs) -> str:
        return obj if isinstance(obj, str) else original_pprint_pformat(obj, *args, **kwargs)

    monkeypatch.setattr(pprint, "pformat", new_pprint_pformat)
© www.soinside.com 2019 - 2024. All rights reserved.