使用unittest.TestCase.assertItemsEqual(或Python 3中的assertCountEqual)时,我遇到了一个让我有些困惑的问题,但我无法在此处找到解决方案,因此我将其后缀发布在这里:

以下单元测试在Python 2和3下均失败。

import six
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)
    __hash__ = None

class Test(unittest.TestCase):
    def test_foo_eq(self):
        self.assertEqual(sorted([Foo()]), sorted([Foo()]))
        six.assertCountEqual(self, [Foo()], [Foo()])
        six.assertCountEqual(self, [Foo(1,2), Foo(2,3)], [Foo(2,3), Foo(1,2)])

unittest.main()

错误消息如下所示:
======================================================================
ERROR: test_foo_eq (__main__.Test)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/tsanders/scripts/one_offs/test_unittest_assert_items_equal2.py", line 20, in test_foo_eq
    six.assertCountEqual(self, [Foo(1,2), Foo(2,3)], [Foo(2,3), Foo(1,2)])
  File "/home/tsanders/.local/lib/python2.7/site-packages/six.py", line 673, in assertCountEqual
    return getattr(self, _assertCountEqual)(*args, **kwargs)
  File "/usr/lib64/python2.7/unittest/case.py", line 929, in assertItemsEqual
    differences = _count_diff_all_purpose(first_seq, second_seq)
  File "/usr/lib64/python2.7/unittest/util.py", line 116, in _count_diff_all_purpose
    if other_elem == elem:
  File "/home/tsanders/scripts/one_offs/test_unittest_assert_items_equal2.py", line 11, in __eq__
    return self.a == other.a and self.b == other.b
AttributeError: 'object' object has no attribute 'a'

----------------------------------------------------------------------
Ran 1 test in 0.000s

FAILED (errors=1)

最佳答案

我必须查看unittest模块的source才能解决此问题。

当要比较的列表的元素不可散列时,assertItemsEqual/assertCountEqual函数回退到a different algorithm来比较列表。该算法使用一个空的object()作为标记,这与Foo类型的对象不相等。

解决方法是按如下方式修改我的__eq__函数:

def __eq__(self, other):
    try:
        return self.a == other.a and self.b == other.b
    except AttributeError:
        return False

关于Python assertItemsEqual/assertCountEqual AttributeError,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/54485612/

10-08 21:33