Search code examples
pythonunit-testingpycharm

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. 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.

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. However, due to how unittest shortens the results, I get results such as this in the diff viewer:

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 '

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 '

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.

I tried to look into unittest code but could not find a configuration option to print full results. There are some variables such as maxDiff and _diffThreshold but they have no impact on this print.

Also, I tried to run this in py.test but there the support in PyCharm was even less (no links even to failed test).

Is there some trick using the difflib with unittest or maybe some other tricks with another Python test framework to do this?


Solution

  • 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. On failure, it gives me the full texts and the PyCharm diff viewer also shows the full diff correctly.

    My assert statement is in a module of its own (t_assert.py), and looks like this

    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..