I know that, when performing assertEqual
on a dictionary, assertDictEqual
is called. Similarly, assertEqual
on a sequence will perform assertSequenceEqual
.
However, when assertDictEqual
is comparing values, it appears not to make use of assertEqual
, and thus assertSequenceEqual
is not called.
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?
I want to avoid using external modules (as suggested in this question) if at all possible, unless they are native django extensions.
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).
Rather than overriding assertDictEqual, why don't you recursively sort your dicts first?
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:
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.