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).
assertEqual() in Python is a unittest library function that is used in unit testing to check the equality of two values. This function will take three parameters as input and return a boolean value depending upon the assert condition. If both input values are equal assertEqual() will return true else return false.
From the context menu, select the corresponding run command. If the directory contains tests that belong to the different testing frameworks, select the configuration to be used. For example, select Run 'All tests in: <directory name>' Run pytest in <directory name>'.
An exception object is created when a Python script raises an exception. If the script explicitly doesn't handle the exception, the program will be forced to terminate abruptly.
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.
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.
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
>
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'].
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():
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:
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With