简体   繁体   English

当多行字符串的单元测试失败时,PyCharm 显示完整差异?

[英]PyCharm show full diff when unittest fails for multiline string?

I am writing some Python unit tests using the "unittest" framework and run them in PyCharm.我正在使用“unittest”框架编写一些 Python 单元测试并在 PyCharm 中运行它们。 Some of the tests compare a long generated string to a reference value read from a file.一些测试将生成的长字符串与从文件中读取的参考值进行比较。 If this comparison fails, I would like to see the diff of the two compared strings using PyCharms diff viewer.如果此比较失败,我想使用 PyCharms 差异查看器查看两个比较字符串的差异。

So the the code is like this:所以代码是这样的:

    actual = open("actual.csv").read()
    expected = pkg_resources.resource_string('my_package', 'expected.csv').decode('utf8')
    self.assertMultiLineEqual(actual, expected)

And PyCharm nicely identifies the test as a failure and provides a link in the results window to click which opens the diff viewer. PyCharm 可以很好地将测试识别为失败,并在结果窗口中提供一个链接,单击该链接可打开差异查看器。 However, due to how unittest shortens the results, I get results such as this in the diff viewer:但是,由于 unittest 如何缩短结果,我在差异查看器中得到了这样的结果:

Left side:左边:

'time[57 chars]ercent 0;1;1;1;1;1;1;1 0;2;1;3;4;2;3;1 0;3;[110 chars]32 ' '时间 [57 个字符]从 0;1;1;1;1;1;1;1 0;2;1;3;4;2;3;1 0;3;[110 个字符]32 '

Right side:右边:

'time[57 chars]ercen 0;1;1;1;1;1;1;1 0;2;1;3;4;2;3;1 0;3;2[109 chars]32 ' 'time[57 个字符]ercen 0;1;1;1;1;1;1;1 0;2;1;3;4;2;3;1 0;3;2[109 个字符]32 '

Now, I would like to get rid of all the [X chars] parts and just see the whole file(s) and the actual diff fully visualized by PyCharm.现在,我想去掉所有 [X 字符] 部分,只查看整个文件和 PyCharm 完全可视化的实际差异。

I tried to look into unittest code but could not find a configuration option to print full results.我试图查看 unittest 代码,但找不到打印完整结果的配置选项。 There are some variables such as maxDiff and _diffThreshold but they have no impact on this print.有一些变量,例如 maxDiff 和 _diffThreshold,但它们对打印没有影响。

Also, I tried to run this in py.test but there the support in PyCharm was even less (no links even to failed test).此外,我尝试在 py.test 中运行它,但 PyCharm 中的支持甚至更少(甚至没有链接到失败的测试)。

Is there some trick using the difflib with unittest or maybe some other tricks with another Python test framework to do this?是否有一些技巧将 difflib 与 unittest 结合使用,或者其他 Python 测试框架使用其他技巧来做到这一点?

The TestCase.maxDiff=None answers given in many places only make sure that the diff shown in the unittest output is of full length. 在许多地方给出的TestCase.maxDiff=None答案只能确保unittest输出中显示的diff是全长的。 In order to also get the full diff in the < Click to see difference > link you have to set MAX_LENGTH. 为了在< Click to see difference >链接中获得完整差异,您必须设置MAX_LENGTH。

import unittest

# Show full diff in unittest
unittest.util._MAX_LENGTH=2000

Source: https://stackoverflow.com/a/23617918/1878199 资料来源: https//stackoverflow.com/a/23617918/1878199

Well, I managed to hack myself around this for my test purposes. 好吧,为了我的测试目的,我设法自己解决了这个问题。 Instead of using the assertEqual method from unittest, I wrote my own and use that inside the unittest test cases. 我没有使用unittest中的assertEqual方法,而是自己编写并在unittest测试用例中使用它。 On failure, it gives me the full texts and the PyCharm diff viewer also shows the full diff correctly. 失败时,它会给我全文,而PyCharm diff查看器也会正确显示完整的差异。

My assert statement is in a module of its own (t_assert.py), and looks like this 我的断言语句在它自己的模块(t_assert.py)中,看起来像这样

def equal(expected, actual):
    msg = "'"+actual+"' != '"+expected+"'"
    assert expected == actual, msg

In my test I then call it like this 在我的测试中,我就这样称呼它

    def test_example(self):
        actual = open("actual.csv").read()
        expected = pkg_resources.resource_string('my_package', 'expected.csv').decode('utf8')
        t_assert.equal(expected, actual)
        #self.assertEqual(expected, actual)

Seems to work so far.. 到目前为止似乎工作..

A related problem here is that unittest.TestCase.assertMultiLineEqual is implemented with difflib.ndiff() .这里的一个相关问题是unittest.TestCase.assertMultiLineEqual是用difflib.ndiff() This generates really big diffs that contain all shared content along with the differences.这会产生非常大的差异,其中包含所有共享内容以及差异。 If you monkey patch to use difflib.unified_diff() instead, you get much smaller diffs that are less often truncated.如果您修改补丁以使用difflib.unified_diff() ,您会得到更小的差异,并且不会经常被截断。 This often avoids the need to set maxDiff.这通常避免了设置 maxDiff 的需要。

import unittest
from unittest.case import _common_shorten_repr
import difflib


def assertMultiLineEqual(self, first, second, msg=None):
    """Assert that two multi-line strings are equal."""
    self.assertIsInstance(first, str, 'First argument is not a string')
    self.assertIsInstance(second, str, 'Second argument is not a string')

    if first != second:
        firstlines = first.splitlines(keepends=True)
        secondlines = second.splitlines(keepends=True)
        if len(firstlines) == 1 and first.strip('\r\n') == first:
            firstlines = [first + '\n']
            secondlines = [second + '\n']
        standardMsg = '%s != %s' % _common_shorten_repr(first, second)
        diff = '\n' + ''.join(difflib.unified_diff(firstlines, secondlines))
        standardMsg = self._truncateMessage(standardMsg, diff)
        self.fail(self._formatMessage(msg, standardMsg))

unittest.TestCase.assertMultiLineEqual = assertMultiLineEqual

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM