为何pytest有时会判定两个字典不相等?
Ah, I see exactly what's going on here—this isn't a random bug at all, it's a quirk of how Django Rest Framework (DRF) handles serializer output. Let's break this down:
The Root Cause: DRF Doesn't Return Native Dictionaries
When you access serializer.data, you're not getting a standard Python dict or list—you're getting DRF's custom ReturnDict (for single objects) or ReturnList (for collections). These classes inherit from native dict/list but add an extra serializer attribute that references the serializer instance that generated them.
Why Equality Assertions Fail (But Your Validation Passes)
Your validation code works because it's almost certainly checking individual key-value pairs (e.g., assert d1['id'] == d2['id']), which ignores the container type and only cares about the actual data. Direct equality checks (assert d1 == d2) can fail in edge cases:
- Nested structure type mismatches: If your serializer has nested serializers, the nested data will also be
ReturnDict/ReturnListinstances. While single-level comparisons betweenReturnDictanddictwork fine, some assertion tools (or custom recursive checks) might validate type consistency alongside content, causing failures. - Python version ordering differences: In Python 3.6 and earlier, native
dicts are unordered, but DRF'sReturnDictinherits fromcollections.OrderedDictto preserve field order. If your expectedd2is a nativedictwith keys in a different order, the equality check will fail—this can seem "random" if you test across environments with different Python versions.
Fixes to Resolve the Issue
Here are three reliable ways to fix this problem:
1. Convert DRF Output to Native Types
Explicitly cast the serializer's output to a native dict or list before asserting equality. Since ReturnDict/ReturnList inherit from native types, this is straightforward:
serialized_data = dict(serializer.data) assert serialized_data == expected_native_dict
For nested structures, this conversion will recursively turn all ReturnList instances into native lists too.
2. Use DRF-Friendly Assertion Methods
Django's test framework includes assertDictEqual and assertListEqual, which are designed to handle DRF's custom container types by comparing content rather than strict type matching:
from django.test import TestCase class MySerializerTestCase(TestCase): def test_serializer_output_matches_expected(self): # ... set up your serializer and expected data ... self.assertDictEqual(serializer.data, expected_dict)
3. Accept DRF's Types as Valid
Since ReturnDict is a subclass of dict, you can adjust your assertions to account for this if you don't need strict native type checks:
from rest_framework.utils.serializer_helpers import ReturnDict assert isinstance(serializer.data, (dict, ReturnDict)) assert serializer.data == expected_dict
This ensures you're checking for compatible types while still validating content equality.
内容的提问来源于stack exchange,提问作者Chathan Driehuys

