【问题标题】:How do I test dictionary-equality with Python's doctest-package?如何使用 Python 的 doctest-package 测试字典相等性?
【发布时间】:2013-03-21 13:51:16
【问题描述】:

我正在为输出字典的函数编写文档测试。 doctest 看起来像

>>> my_function()
{'this': 'is', 'a': 'dictionary'}

当我运行它时,它失败了

Expected:
    {'this': 'is', 'a': 'dictionary'}
Got:
    {'a': 'dictionary', 'this': 'is'}

我对这次失败原因的最佳猜测是 doctest 不是检查字典相等性,而是检查__repr__ 相等性。 This post 表示有某种方法可以欺骗 doctest 检查字典是否相等。我该怎么做?

【问题讨论】:

  • 因为 dict 是无序的,所以不能按原样使用 dict。您必须将其转换为有序对象
  • 下面列出的答案都在doctest文档中:docs.python.org/2/library/doctest.html#warnings
  • @ornoone 但是为什么呢?它们是相等的对象,这就是 doctest 应该检查的内容。
  • 正如在接受的答案中所说,检查的是您的两个对象的 repr,而不是它们的内容。因为repr(a) != repr(b) doctest 认为你的对象是不同的。如果a == b 正常,则事件。我认为之所以如此,是因为 doctest 在 doc 中,并且应该易于阅读,并且通过 repr 检查,它是可读的。

标签: python dictionary doctest


【解决方案1】:

另一个好方法是使用pprint(在标准库中)。

>>> import pprint
>>> pprint.pprint({"second": 1, "first": 0})
{'first': 0, 'second': 1}

根据它的源代码,它正在为你排序字典:

http://hg.python.org/cpython/file/2.7/Lib/pprint.py#l158

items = _sorted(object.items())

【讨论】:

  • 这很好,但是 python 开发者 don't recommend this 因为他们不保证跨版本的 pprint 稳定性。
  • 另外,此解决方案必须适用于其他数据类型(例如 set)。
  • 这里的好处是一旦断言失败,pprint 将显示一个有用的差异。如果 pprint 实现在 Python 版本之间发生变化,那么我们需要调整我们的测试或者只是在我们的代码中复制实现以保持其稳定。
【解决方案2】:

Doctest 本身不检查__repr__ 是否相等,它只是检查输出是否完全相同。您必须确保打印的任何内容对于同一个字典都是相同的。你可以用这个单线做到这一点:

>>> sorted(my_function().items())
[('a', 'dictionary'), ('this', 'is')]

尽管您的解决方案的这种变化可能更简洁:

>>> my_function() == {'this': 'is', 'a': 'dictionary'}
True

【讨论】:

  • 您的解决方案更简洁,但它无法告诉您 my_function 实际评估的内容。
  • pprint 解决方案看起来更干净,请参阅 charlax 的回答
  • 但是如果它是一个文档示例并且我想展示一个真实的输入和真实的输出呢?有没有办法让它检查相等性而不是精确的字符串?
  • 您提供的第二个变体非常适合我的简单文档测试。谢谢!
  • pprint-解决方案并不总是适用于set doctests - 没有保证的顺序。如果你以后想知道它被评估为什么,你可以做my_function() == {'this': 'is', 'a': 'dictionary'} or my_function()
【解决方案3】:

我最终使用了这个。哈克,但它有效。

>>> p = my_function()
>>> {'this': 'is', 'a': 'dictionary'} == p
True

【讨论】:

  • 我不认为这是 hacky(虽然我会写 p == {etc})——这是 the docs 相关部分中第一个推荐的技术。
  • 为什么不my_function() == {'this': 'is', 'a': 'dictionary'}
  • 这里的缺点是一旦断言失败,你不知道哪些键、值是错误的。使用pprint 的解决方案会显示出有用的差异。
【解决方案4】:

通过 dict.items() 将其变成一个列表,然后对其进行排序...

>>> l = my_function().items()
>>> l.sort()
>>> l
[('a', 'dictionary'), ('this', 'is')]

【讨论】:

  • 或单行:sorted( my_function().items())
【解决方案5】:

大部分已经在这里说了..无论如何 JSYK:doctest 文档中有一个专门的部分:

https://docs.python.org/3.5/library/doctest.html#warnings

【讨论】:

    【解决方案6】:

    您可以在您的文档测试中创建unittest.TestCase 类的实例,并使用它来比较字典:

    def my_function(x):
        """
        >>> from unittest import TestCase
        >>> t = TestCase()
    
        >>> t.assertDictEqual(
        ...     my_function('a'),
        ...     {'this': 'is', 'a': 'dictionary'}
        ... )
    
        >>> t.assertDictEqual(
        ...     my_function('b'),
        ...     {'this': 'is', 'b': 'dictionary'}
        ... )
    
        """
        return {'this': 'is', x: 'dictionary'}
    

    注意:这种方法比简单地检查字典是否相等要好,因为它会显示两个字典之间的差异。

    【讨论】:

      【解决方案7】:

      我发现在测试任意嵌套数据时在我的 doctests 中使用 deepdiff 包很有用。例如:

      def something_complicated():
          """
          >>> from deepdiff import DeepDiff
          >>> DeepDiff(something_complicated(),
          ...          {'expected': {'output': ['a', 'b', 'c']}},
          ...          ignore_order=True)
          {}
          """
          items = ['a', 'b', 'c']
          random.shuffle(items)
          return {'expected': {'output': items}}
      

      【讨论】:

        猜你喜欢
        • 2020-10-30
        • 2011-04-17
        • 1970-01-01
        • 1970-01-01
        • 2011-11-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多