Python 如何将 assertSequenceEqual 应用于值来实现 assertDictEqual
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18464095/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to achieve assertDictEqual with assertSequenceEqual applied to values
提问by sapi
I know that, when performing assertEqual
on a dictionary, assertDictEqual
is called. Similarly, assertEqual
on a sequence will perform assertSequenceEqual
.
我知道,在assertEqual
字典上执行时,会assertDictEqual
被调用。同样,assertEqual
在一个序列上将执行assertSequenceEqual
.
However, when assertDictEqual
is comparing values, it appears not to make use of assertEqual
, and thus assertSequenceEqual
is not called.
但是,在assertDictEqual
比较值时,似乎没有使用assertEqual
,因此assertSequenceEqual
不会被调用。
Consider the following simple dictionaries:
考虑以下简单的字典:
lst1 = [1, 2]
lst2 = [2, 1]
d1 = {'key': lst1}
d2 = {'key': lst2}
self.assertEqual(lst1, lst2) # True
self.assertEqual(d1, d2) # False ><
How can I test dictionaries such as d1
and d2
such that their equality is properly compared, by recursively applying assertEqual
-like semantics to values?
如何通过递归地将类似语义应用于值来测试诸如d1
和d2
这样的字典,以便正确比较它们的相等性assertEqual
?
I want to avoid using external modules (as suggested in this question) if at all possible, unless they are native django extensions.
如果可能的话,我想避免使用外部模块(如本问题所建议的那样),除非它们是本机 django 扩展。
EDIT
编辑
Essentially, what I am after is a built in version of this:
本质上,我所追求的是一个内置版本:
def assertDictEqualUnorderedValues(self, d1, d2):
for k,v1 in d1.iteritems():
if k not in d2:
self.fail('Key %s missing in %s'%(k, d2))
v2 = d2[k]
if isinstance(v1, Collections.iterable) and not isinstance(v1, basestring):
self.assertValuesEqual(v1, v2)
else:
self.assertEqual(v1, v2)
The problem with the above code is that the error messages are not as nice as the builtin asserts, and there's probably edge cases I've ignored (as I just wrote that off the top of my head).
上面代码的问题在于错误消息不像内置断言那么好,而且可能有一些边缘情况我已经忽略了(因为我只是把它写在我的头上)。
回答by martineau
The TestCase.assertEqual()
method calls the class' assertDictEqual()
for dicts
, so just override that in your subclass derivation. If you only use other assertXXX
methods in the method, the error messages should be almost as nice as the built-in asserts -- but if not you can provide a msg
keyword argument when you call them to control what is displayed.
该TestCase.assertEqual()
方法调用类' assertDictEqual()
for dicts
,因此只需在您的子类派生中覆盖它。如果您只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()
Output:
输出:
> python unittest_test.py
.
---------------------------------------------------------------------->
Ran 1 test in 0.000s
OK
>
回答by Chris Villa
Rather than overriding assertDictEqual, why don't you recursively sort your dicts first?
与其覆盖 assertDictEqual,不如先递归地对 dicts 进行排序?
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
Then sort, and use normal assertDictEqual:
然后排序,并使用正常的 assertDictEqual:
dict1 = deep_sort(dict1)
dict2 = deep_sort(dict2)
self.assertDictEqual(dict1, dict2)
This approach has the benefit of not caring about how many levels deep your lists are.
这种方法的好处是不关心列表的深度。
回答by Robin van Leeuwen
I had the same problem, i had to test if the fields of a model where correct. And MyModel._meta.get_all_field_names() sometimes returns ['a','b'] and sometimes ['b','a'].
我遇到了同样的问题,我必须测试模型的字段是否正确。MyModel._meta.get_all_field_names() 有时返回 ['a','b'],有时返回 ['b','a']。
When i run:
当我运行时:
self.assertEqual(MyModel._meta.get_all_field_names(), ['a', 'b'])
it sometimes fails.
它有时会失败。
I solved it by putting both values in a set():
我通过将两个值放在一个 set() 中来解决它:
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
This will not work (returns True) with:
这将不起作用(返回 True):
self.assertEqual(set(['a','a','b','a']), set(['a','b'])) # Also true
But since i'm checking for field names of a model , and those are unique, this is good by me.
但是由于我正在检查模型的字段名称,并且这些名称是唯一的,因此这对我来说很好。