Unittest中如何忽略顺序比较嵌套列表以通过断言?
嘿,我来帮你搞定这个单元测试的小问题!你遇到的核心问题是unittest里的assertEqual会严格检查列表元素的顺序,但你的实际返回结果和预期结果只是元素顺序不同,内容完全一致对吧?
先把你碰到的错误信息贴出来,方便对照:
AssertionError: Lists differ: [['1', 14], ['4', 1], ['2', 5], ['3', 7]] != [['1' , 14], ['2', 5], ['3', 7], ['4', 1]]
First differing element 1:
['4', 1]
['2', 5]
- [['1', 14], ['4', 1], ['2', 5], ['3', 7]]
- [['1', 14], ['2', 5], ['3', 7], ['4', 1]]
下面给你几个实用的解决方案,按推荐程度排序:
方案1:用assertCountEqual直接忽略顺序(最推荐)
如果你用的是Python 3.2及以上版本的unittest框架,直接把self.assertEqual换成self.assertCountEqual就搞定了。这个方法专门用来检查两个序列的元素是否完全相同(包括每个元素的出现次数),完全不关心顺序:
self.assertCountEqual(sale, [['1',14], ['2',5], ['3',7], ['4',1]])
要是你用的是Python 2.x或者更早的Python 3版本,这个方法曾叫assertItemsEqual,功能是一模一样的。
方案2:先排序再断言
如果因为项目限制没法用assertCountEqual,可以先把实际结果和预期结果按统一规则排序,再用assertEqual检查。因为是嵌套列表,我们可以指定按子列表的第一个元素排序(当然你也可以选第二个数字元素,只要规则统一就行):
# 对实际结果和预期结果按子列表的第一个元素排序 sorted_actual = sorted(sale, key=lambda x: x[0]) sorted_expected = sorted([['1',14], ['2',5], ['3',7], ['4',1]], key=lambda x: x[0]) self.assertEqual(sorted_actual, sorted_expected)
排序后两个列表的顺序完全一致,assertEqual自然就能通过测试了。
方案3:转成集合(注意局限性)
如果你的嵌套列表里所有子元素都是可哈希的(比如字符串、数字),也可以把每个子列表转成元组(列表不可哈希,元组可以),再转换成集合来断言:
actual_set = set(tuple(item) for item in sale) expected_set = set(tuple(item) for item in [['1',14], ['2',5], ['3',7], ['4',1]]) self.assertEqual(actual_set, expected_set)
⚠️ 注意:这个方法只适合没有重复元素的场景,因为集合会自动去重,要是你的列表里有重复项,用这个方法会导致测试不准确,所以优先选前两种方案。
内容的提问来源于stack exchange,提问作者Tom J Muthirenthi

