Python 如何使用应用于值的assertSequenceEqual实现assertDictEqual
我知道,在字典上执行Python 如何使用应用于值的assertSequenceEqual实现assertDictEqual,python,unit-testing,python-unittest,Python,Unit Testing,Python Unittest,我知道,在字典上执行assertEqual时,会调用assertDictEqual。类似地,序列上的assertEqual将执行assertSequenceEqual 但是,当比较值时,assertDictEqual似乎没有使用assertEqual,因此不会调用assertSequenceEqual 考虑以下简单词典: lst1 = [1, 2] lst2 = [2, 1] d1 = {'key': lst1} d2 = {'key': lst2} self.assertEqual(lst
assertEqual
时,会调用assertDictEqual
。类似地,序列上的assertEqual
将执行assertSequenceEqual
但是,当比较值时,assertDictEqual
似乎没有使用assertEqual
,因此不会调用assertSequenceEqual
考虑以下简单词典:
lst1 = [1, 2]
lst2 = [2, 1]
d1 = {'key': lst1}
d2 = {'key': lst2}
self.assertEqual(lst1, lst2) # True
self.assertEqual(d1, d2) # False ><
上面代码的问题是错误消息没有内置断言的那么好,并且可能有一些我忽略的边缘情况(正如我刚才在头上写的那样)。TestCase.assertEqual()方法为
dicts调用类'assertDictEqual()
,所以只需在子类派生中重写它。如果在方法中只使用其他assertXXX
方法,则错误消息应该与内置断言一样好——但如果不是这样,则可以在调用它们以控制显示内容时提供msg
关键字参数
import collections
import unittest
class TestSOquestion(unittest.TestCase):
def setUp(self):
pass # whatever...
def assertDictEqual(self, d1, d2, msg=None): # assertEqual uses for dicts
for k,v1 in d1.iteritems():
self.assertIn(k, d2, msg)
v2 = d2[k]
if(isinstance(v1, collections.Iterable) and
not isinstance(v1, basestring)):
self.assertItemsEqual(v1, v2, msg)
else:
self.assertEqual(v1, v2, msg)
return True
def test_stuff(self):
lst1 = [1, 2]
lst2 = [2, 1]
d1 = {'key': lst1}
d2 = {'key': lst2}
self.assertItemsEqual(lst1, lst2) # True
self.assertEqual(d1, d2) # True
if __name__ == '__main__':
unittest.main()
输出:
python unittest\u test.py
.
---------------------------------------------------------------------->
在0.000秒内运行了1次测试
好啊
>
与其重写assertDictEqual,不如先对DICT进行递归排序
def deep_sort(obj):
"""
Recursively sort list or dict nested lists
"""
if isinstance(obj, dict):
_sorted = {}
for key in sorted(obj):
_sorted[key] = deep_sort(obj[key])
elif isinstance(obj, list):
new_list = []
for val in obj:
new_list.append(deep_sort(val))
_sorted = sorted(new_list)
else:
_sorted = obj
return _sorted
然后进行排序,并使用普通assertDictEqual:
dict1 = deep_sort(dict1)
dict2 = deep_sort(dict2)
self.assertDictEqual(dict1, dict2)
这种方法的好处是不关心列表的深度。我也有同样的问题,我必须测试模型的字段是否正确。和MyModel._meta.get_all_field_names()有时返回['a','b'],有时返回['b','a'] 当我跑步时:
self.assertEqual(MyModel._meta.get_all_field_names(), ['a', 'b'])
它有时会失败
我通过将两个值放在一个集合()中解决了这个问题:
这在以下情况下不起作用(返回True):
但是,由于我正在检查模型的字段名,并且这些字段名是唯一的,这对我来说很好。对于
unittest
模块,self.assertEqual(lst1,lst2)
不是真的-->AssertionError:list不同:[1,2]!=[2,1]
@martineau-我的错误;我误读了文件的那一部分。我在寻找一个等价的asserteSequal
而不是assertSequenceEqual
好吧,如果你使lst1
和lst2
相同,那么第一个assertEqual
成功,那么第二个也会成功“正在寻找与AssertSequenceQual
等效的,而不是assertSequenceEqual
“对我来说毫无意义。我的观点是,您问题中的代码在两个列表上使用的是assertEqual
,两个列表中的项顺序不同,该断言将失败。如果您控制创建数据结构的代码,可能应该使用集合而不是列表。我无法保证列表的顺序。这些测试是针对django框架的,我不能依赖于测试集和预期结果之间的数据库查询顺序是相同的。我所关心的是API以某种顺序给了我正确的值。好吧,但我仍然不明白为什么/如何期望第一个assertEqual(lst1,lst2)
在代码中为真。此解决方案不适用于深度嵌套的dicts+列表。基于排序的解决方案确实如此。您可以使用集合表示法来改进这一点,而不是set(['a','b'])
尝试{'a','b'}
。此外,还有一个函数self.assertSetEqual({'a','a','b','a'},{'a','b'})
,它将检查两个集合之间的差异,如果它们不包含完全相同的元素,则会失败。Exception:'
self.assertEqual(MyModel._meta.get_all_field_names(), ['a', 'b'])
self.assertEqual(set(MyModel._meta.get_all_field_names()), set(['a', 'b'])) #true
self.assertEqual(set(MyModel._meta.get_all_field_names()), set(['b', 'a'])) #true
self.assertEqual(set(['a','a','b','a']), set(['a','b'])) # Also true