【问题标题】:How to prevent truncating of string in unit test python如何防止在单元测试python中截断字符串
【发布时间】:2017-05-08 08:06:56
【问题描述】:

我正在用 Python 为我的程序做一个单元测试,我想做一个 assertEquals 测试。

我的代码如下所示:

class UnitTest(unittest.TestCase):
      def test_parser(self):
          self.assertEquals(parser,"some long string", "String is not equal")

但是,由于我的字符串太长,我得到了类似testing[471 chars]0 != testing[473 chars] 的内容。我想看看两个字符串之间的确切区别是什么,而不是看到截断的字符串。

有人知道如何解决这个问题吗?

【问题讨论】:

  • 你的意思是assertEquals 输出没有显示完整的输出?
  • 是的,它没有显示完整的输出。相反,我分别看到类似 [471 chars] 和 [473 chars] 的内容。
  • 您是否尝试将self.maxDiff 设置为更高的值或None?断言消息会告诉你这一点。
  • 我尝试将 maxDiff 设置为 None 但仍然收到相同的输出。
  • 你在哪里设置的?在测试功能本身?在测试用例上作为类属性?

标签: python string unit-testing testing truncated


【解决方案1】:

所以,我提出了这个问题,因为我遇到了一个问题,我使用 assertEqual()self.maxDiff = None 不会导致显示完整的输出。追查发现,因为两个对象的类型不同(一个是列表,一个是生成器),所以没有使用使用self.maxDiff 的代码路径。因此,如果您遇到需要完整差异且 self.maxDiff 不起作用的问题,请确保您的两个比较对象的类型相同。

【讨论】:

  • 为了使这种情况更加有害,差异渲染可能会使它们看起来像是同一类型,而实际上并非如此。在测试序列化程序时,您会得到 OrderedDict 而不是 dict,因此比较这两个 self.maxDiff 无效。你必须做self.assertEqual(dict(result),expected_result))
  • 这并不试图回答最初的问题:如果它们不同,如​​何获取两个字符串的完整转储(不缩短)。
【解决方案2】:

要将[... chars][truncated]... 替换为实际字符(无论多长,也无论比较值的类型是什么),请将其添加到您的*_test.py 文件中:

if 'unittest.util' in __import__('sys').modules:
    # Show full diff in self.assertEqual.
    __import__('sys').modules['unittest.util']._MAX_LENGTH = 999999999

确实,正如其他答案所指出的那样,设置 self.maxDiff = None 没有帮助,它不会使 [... chars] 消失。但是,此设置有助于显示其他类型的长差异,所以我的建议是两者都做。

【讨论】:

  • 谢谢你,所有其他答案都指向maxDiff = None,这没有帮助。
【解决方案3】:

unittest.TestCase.assertEquals 尝试为您提供字符串中的实际差异,同时使文本适合您的屏幕

为此,它会截断公共部分,因此没有差异的部分会被截断为[<count> chars]块:

>>> case.assertEqual('foo' * 200, 'foo' * 100 + 'bar' + 'foo' * 99)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/mjpieters/Development/Library/buildout.python/parts/opt/lib/python3.6/unittest/case.py", line 821, in assertEqual
    assertion_func(first, second, msg=msg)
  File "/Users/mjpieters/Development/Library/buildout.python/parts/opt/lib/python3.6/unittest/case.py", line 1194, in assertMultiLineEqual
    self.fail(self._formatMessage(msg, standardMsg))
  File "/Users/mjpieters/Development/Library/buildout.python/parts/opt/lib/python3.6/unittest/case.py", line 666, in fail
    raise self.failureException(msg)
AssertionError: 'foof[291 chars]oofoofoofoofoofoofoofoofoofoofoofoofoofoofoofo[255 chars]ofoo' != 'foof[291 chars]oofoobarfoofoofoofoofoofoofoofoofoofoofoofoofo[255 chars]ofoo'
Diff is 1819 characters long. Set self.maxDiff to None to see it.

在上面的示例中,两个字符串共享一个长前缀,通过将两个前缀中的 291 个字符替换为 [291 chars] 来缩短前缀。它们还共享一个长后缀,通过将文本替换为[255 chars],在两个位置再次缩短。

实际差异仍在显示,就在中间。

当然,当你把这个差值弄得太长时,甚至差值也会被截断:

>>> case.assertEqual('foo' * 200, 'foo' * 80 + 'bar' * 30 + 'foo' * 80)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/mjpieters/Development/Library/buildout.python/parts/opt/lib/python3.6/unittest/case.py", line 821, in assertEqual
    assertion_func(first, second, msg=msg)
  File "/Users/mjpieters/Development/Library/buildout.python/parts/opt/lib/python3.6/unittest/case.py", line 1194, in assertMultiLineEqual
    self.fail(self._formatMessage(msg, standardMsg))
  File "/Users/mjpieters/Development/Library/buildout.python/parts/opt/lib/python3.6/unittest/case.py", line 666, in fail
    raise self.failureException(msg)
AssertionError: 'foof[231 chars]oofoofoofoofoofoofoofoofoofoofoofoofoofoofoofo[315 chars]ofoo' != 'foof[231 chars]oofoobarbarbarbarbarbarbarbarbarbarbarbarbarba[285 chars]ofoo'
Diff is 1873 characters long. Set self.maxDiff to None to see it.

在这里,常见的后缀开始不同,但差异的开始仍然可见,应该可以帮助您找出文本出错的地方。

如果这仍然不够,您可以增加或消除差异限制。将TestCase.maxDiff attribute设置为更大的数字(默认为8 * 80,80行文字),或者设置为None以完全消除:

self.maxDiff = None

请注意,除非您的字符串包含 换行符,否则差异可能是不可读的:

AssertionError: 'foof[231 字符]oofoofoofoofoofoofoofoofoofoofoofoofoofoofoofo[315 个字符]ofoo' != 'foof[231 个字符]oofoobarbarbarbarbarbarbarbarbarbarbarbarbarba[285 字符]ofoo' - foofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoo ?
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^ + foofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoobarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarfoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoo ?
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

在这种情况下,包装您的输入和输出文本可能更有用:

from textwrap import wrap

self.maxDiff = None
self.assertEquals(wrap(parser), wrap("some long string"), "String is not equal")

只是为了让您获得更好、更易读的差异输出:

>>> from textwrap import wrap
>>> case.assertEqual(wrap('foo' * 200), wrap('foo' * 80 + 'bar' * 30 + 'foo' * 80))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/mjpieters/Development/Library/buildout.python/parts/opt/lib/python3.6/unittest/case.py", line 821, in assertEqual
    assertion_func(first, second, msg=msg)
  File "/Users/mjpieters/Development/Library/buildout.python/parts/opt/lib/python3.6/unittest/case.py", line 1019, in assertListEqual
    self.assertSequenceEqual(list1, list2, msg, seq_type=list)
  File "/Users/mjpieters/Development/Library/buildout.python/parts/opt/lib/python3.6/unittest/case.py", line 1001, in assertSequenceEqual
    self.fail(msg)
  File "/Users/mjpieters/Development/Library/buildout.python/parts/opt/lib/python3.6/unittest/case.py", line 666, in fail
    raise self.failureException(msg)
AssertionError: Lists differ: ['foo[244 chars]oofoofoofoofoofoofoofoofoofoofoofoofoofoofoof'[336 chars]foo'] != ['foo[244 chars]oofoobarbarbarbarbarbarbarbarbarbarbarbarbarb'[306 chars]foo']

First differing element 3:
'foofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoof'
'foofoofoofoofoofoofoofoofoofoobarbarbarbarbarbarbarbarbarbarbarbarbarb'

  ['foofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoof',
   'oofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofo',
   'ofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoo',
-  'foofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoof',
-  'oofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofo',
+  'foofoofoofoofoofoofoofoofoofoobarbarbarbarbarbarbarbarbarbarbarbarbarb',
+  'arbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarfoofoofoofoofoofoofo',
   'ofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoo',
   'foofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoof',
   'oofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofo',
-  'ofoofoofoofoofoofoofoofoofoofoofoofoofoo']
+  'ofoofoofoo']

【讨论】:

  • 建议的解决方案 (wrap(...)) 仅适用于字符串;如果 self.assertEqual 在非字符串类型(其 repr 很长)上调用,则会引发异常。有关适用于所有类型的解决方案,请参阅我的答案。
猜你喜欢
  • 2013-10-10
  • 2021-03-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-07-05
  • 2011-04-24
相关资源
最近更新 更多