Python unittest - 断言包含列表的字典

16 投票
4 回答
17942 浏览
提问于 2025-04-17 13:28

在为我的类写测试的时候,我遇到了一个有趣的简单问题。我想要比较两个字典,确保它们是相等的,但这两个字典里包含的列表可能排序不一样,这就导致测试失败了。

举个例子:

def test_myobject_export_into_dictionary(self):
    obj = MyObject()
    resulting_dictionary = {
            'state': 2347,
            'neighbours': [1,2,3]
        }
    self.assertDictEqual(resulting_dictionary, obj.exportToDict())

这个测试有时候会失败,具体取决于列表中元素的顺序。

FAIL: test_myobject_export_into_dictionary
------------------------------------
-  'neighbours': [1,2,3],
+  'neighbours': [1,3,2],

有没有简单的方法可以做到这一点呢?

我在考虑用 set 代替 list,或者在比较之前先对列表进行排序。

4 个回答

0

那用 all 怎么样呢:

assert all( (k,v) in resulting_dictionary.iteritems() 
            for (k,v) in obj.exportToDict().iteritems() )

我在用 py.test 的时候会这样做,但我觉得你也可以用这个方法。


有个评论者提到顺序会影响结果——这说得对……那我就用集合吧。

2

你可以这样做:

a = {i:sorted(j) if isinstance(j, list) else j for i,j in resulting_dictionary.iteritems()}
b = {i:sorted(j) if isinstance(j, list) else j for i,j in obj.exportToDict().iteritems()}
self.assertDictEqual(a, b)
8

你可以试试 PyHamcrest (示例已修正)

assert_that(obj.exportToDict(), has_entries(
                                    { 'state': 2347,
                                      'neighbours': contains_inanyorder(1,2,3) }))

(第一个值2347实际上是被隐式地包裹在一个 equal_to 匹配器里面的。)

撰写回答