在Python 2下使用unittest.TestCase.assertItemsEqual
函数遇到了一个有趣的情况;在此张贴我的发现以供后代使用。
下面的单元测试应该在Python 2下成功完成:
import unittest
class Foo(object):
def __init__(self, a=1, b=2):
self.a = a
self.b = b
def __repr__(self):
return '({},{})'.format(self.a, self.b)
def __eq__(self, other):
return self.a == other.a and self.b == other.b
def __lt__(self, other):
return (self.a, self.b) < (other.a, other.b)
class Test(unittest.TestCase):
def test_foo_eq(self):
self.assertEqual(sorted([Foo()]), sorted([Foo()]))
self.assertItemsEqual([Foo()], [Foo()])
unittest.main()
以下是输出:
======================================================================
FAIL: test_foo_eq (__main__.Test)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/tsanders/scripts/one_offs/test_unittest_assert_items_equal2.py", line 17, in test_foo_eq
self.assertItemsEqual([Foo()], [Foo()])
AssertionError: Element counts were not equal:
First has 1, Second has 0: (1,2)
First has 0, Second has 1: (1,2)
----------------------------------------------------------------------
Ran 1 test in 0.000s
FAILED (failures=1)
自docs状态以来,这非常令人困惑:
[
assertItemsEqual
与assertEqual(sorted(expected), sorted(actual))
等效,但它也适用于不可哈希对象序列。
相同的测试在Python 3下通过(由于名称已更改,因此将self.assertItemsEqual
交换为self.assertCountEqual
之后。
编辑:发布此问题后,我确实找到了this个其他问题,涉及未定义__eq__
和__hash__
的情况。
答案 0 :(得分:1)
要使测试在Python 2和3下都能通过,我必须将__hash__ = None
行添加到Foo
。
assertItemsEqual
/ assertCountEqual
函数采用不同的代码路径,具体取决于每个列表中的项目是否可哈希。并根据docs:
如果一个类没有定义
__cmp__()
或__eq__()
方法,那么它也不应定义__hash__()
操作;如果它定义了__cmp__()
或__eq__()
而不是__hash__()
,则其实例将无法在哈希集合中使用。
请记住,在定义__hash__
时,Python 2和3在__eq__
方面具有不同的行为:
__eq__
不会影响默认提供的__hash__
,但尝试在散列容器中使用该项会导致实现定义的行为(例如,键可能会重复,因为它们会重复即使__eq__
返回True
也具有不同的哈希值。__eq__
会将__hash__
设置为None
。从Python 2.6开始,__hash__
可以显式设置为None
,以使类不可散列。在我的案例中,要求使assertItemsEqual
使用依赖于__eq__
而不是__hash__
的正确比较算法。