Compare unordered lists that contain dictionaries in unittest
For unordered lists containing dictionaries, use assertCountEqual() rather than converting the lists to sets or sorting them. Dictionaries are unhashable, so set conversion raises TypeError. They also have no general ordering relative to another dictionary, so sorting a list of them raises TypeError in Python 3.
The first pair below contains the same two mappings in opposite orders. assertCountEqual() passes because it compares members without requiring an order. The second pair adds another {"id": 2} on the right. That assertion fails, and the runner records one failure: the method preserves multiplicity rather than merely asking whether every distinct mapping occurs somewhere.
The script catches the two unsuitable-operation exceptions, then runs the two focused test methods with an in-memory TestResult. Its final assertions make the intended contrast explicit. This is not a deep comparison rule for arbitrary custom objects; equality is still determined by the objects' == behavior. The example is deliberately small, so it demonstrates comparison semantics rather than establishing a performance characteristic for larger inputs.
assertCountEqual is available in Python 3.2 and later and documents sequence comparison that checks the same elements with the same counts, including unhashable objects.
AI assistance disclosure: this article and its synthetic example were prepared with AI assistance.
Example
import unittest
left = [{"id": 1}, {"id": 2}]
permuted = [{"id": 2}, {"id": 1}]
with_duplicate = [{"id": 2}, {"id": 1}, {"id": 2}]
class MappingListTests(unittest.TestCase):
def test_permuted_lists_match(self):
self.assertCountEqual(left, permuted)
def test_duplicate_is_reported(self):
self.assertCountEqual(left, with_duplicate)
def exception_name(operation):
try:
operation()
except TypeError as error:
return type(error).__name__
set_error = exception_name(lambda: set(left))
sort_error = exception_name(lambda: sorted(left))
result = unittest.TestResult()
unittest.defaultTestLoader.loadTestsFromTestCase(MappingListTests).run(result)
assert set_error == "TypeError"
assert sort_error == "TypeError"
assert result.testsRun == 2
assert len(result.failures) == 1
print(f"set conversion: {set_error}")
print(f"sorting: {sort_error}")
print(f"assertCountEqual failures: {len(result.failures)}")
Expected output:
set conversion: TypeError
sorting: TypeError
assertCountEqual failures: 1