You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何结合assertDictEqual与pandas.testing.assert_frame_equal进行测试?

解决方案:结合assertDictEqual与pandas.testing.assert_frame_equal对比嵌套字典中的DataFrame

问题核心在于:Python标准库的assertDictEqual通过对象身份(内存地址)判断相等性,而Pandas DataFrame需要按内容(数据、结构、类型等)比较,直接使用assertDictEqual会因两个DataFrame是不同对象而断言失败。以下是几种经典解决方法:


方法1:递归遍历字典,针对性断言

编写辅助函数递归遍历嵌套字典每一层:遇到DataFrame就用pandas.testing.assert_frame_equal做内容比对,遇到子字典就递归处理,其他类型用普通相等性检查。

import pandas as pd
import unittest

def function_to_test():
    data = {'Name': ['Tom', 'Joseph'], 'Age': [20, 21]}
    df = pd.DataFrame(data)
    return {"key_first_level": {"key_second_level": df}} 

def assert_dict_with_frames_equal(expected, actual):
    # 先确认键集合完全一致
    assert set(expected.keys()) == set(actual.keys()), "字典键集合不匹配"
    
    for key in expected:
        val_exp = expected[key]
        val_act = actual[key]
        
        # 处理DataFrame类型
        if isinstance(val_exp, pd.DataFrame) and isinstance(val_act, pd.DataFrame):
            pd.testing.assert_frame_equal(val_exp, val_act)
            # 可选:不需要严格检查dtype时,添加check_dtype=False参数
        
        # 处理嵌套字典
        elif isinstance(val_exp, dict) and isinstance(val_act, dict):
            assert_dict_with_frames_equal(val_exp, val_act)
        
        # 其他类型直接比较值
        else:
            assert val_exp == val_act, f"键[{key}]的值不匹配:{val_exp} vs {val_act}"

class TestFunction(unittest.TestCase):
    def test_function_to_test(self):
        data = {'Name': ['Tom', 'Joseph'], 'Age': [20, 21]}
        df = pd.DataFrame(data)
        expected_dict = {"key_first_level": {"key_second_level": df}}
        actual_dict = function_to_test()
        
        # 调用自定义断言函数
        assert_dict_with_frames_equal(expected_dict, actual_dict)

if __name__ == '__main__':
    unittest.main()

优点:

  • 灵活适配任意深度的嵌套字典
  • 可轻松扩展支持其他Pandas对象(如pd.Series,只需添加对应类型判断)
  • 逻辑清晰,便于调试

方法2:扩展unittest的断言逻辑

通过unittest.TestCase.addTypeEqualityFunc方法,给dict类型注册自定义比较函数,这样可直接用self.assertDictEqual,它会自动处理字典中的DataFrame。

import pandas as pd
import unittest

def function_to_test():
    data = {'Name': ['Tom', 'Joseph'], 'Age': [20, 21]}
    df = pd.DataFrame(data)
    return {"key_first_level": {"key_second_level": df}} 

def compare_dict_with_frames(test_case, expected, actual, msg=None):
    # 先检查键集合
    test_case.assertEqual(set(expected.keys()), set(actual.keys()), msg=msg)
    
    for key in expected:
        exp_val = expected[key]
        act_val = actual[key]
        
        if isinstance(exp_val, pd.DataFrame) and isinstance(act_val, pd.DataFrame):
            pd.testing.assert_frame_equal(exp_val, act_val, msg=msg)
        elif isinstance(exp_val, dict) and isinstance(act_val, dict):
            compare_dict_with_frames(test_case, exp_val, act_val, msg=msg)
        else:
            test_case.assertEqual(exp_val, act_val, msg=f"键[{key}]不匹配")

class TestFunction(unittest.TestCase):
    def setUp(self):
        # 为dict类型注册自定义比较逻辑
        self.addTypeEqualityFunc(dict, compare_dict_with_frames)

    def test_function_to_test(self):
        data = {'Name': ['Tom', 'Joseph'], 'Age': [20, 21]}
        df = pd.DataFrame(data)
        expected_dict = {"key_first_level": {"key_second_level": df}}
        actual_dict = function_to_test()
        
        # 直接用标准的assertDictEqual即可
        self.assertDictEqual(expected_dict, actual_dict)

if __name__ == '__main__':
    unittest.main()

优点:

  • 符合unittest原生风格,无需修改原有测试代码的断言调用
  • 一次注册,整个测试类的所有assertDictEqual都能自动处理DataFrame

方法3:转换DataFrame为字典(仅适用于简单场景)

若字典中的DataFrame结构简单(无datetime、categorical等复杂类型),可将预期和实际的DataFrame都转换成字典,再用assertDictEqual比较。

import pandas as pd
import unittest

def function_to_test():
    data = {'Name': ['Tom', 'Joseph'], 'Age': [20, 21]}
    df = pd.DataFrame(data)
    return {"key_first_level": {"key_second_level": df}} 

class TestFunction(unittest.TestCase):
    def test_function_to_test(self):
        data = {'Name': ['Tom', 'Joseph'], 'Age': [20, 21]}
        df = pd.DataFrame(data)
        # 预期字典中的DataFrame转成dict
        expected_dict = {"key_first_level": {"key_second_level": df.to_dict()}}
        
        actual_dict = function_to_test()
        # 实际返回的字典中的DataFrame也转成dict
        actual_converted = {
            k: {sub_k: sub_v.to_dict() for sub_k, sub_v in v.items()}
            for k, v in actual_dict.items()
        }
        
        self.assertDictEqual(expected_dict, actual_converted)

if __name__ == '__main__':
    unittest.main()

缺点:

  • 复杂类型转换后可能出现不一致(如datetime会变成字符串或时间戳)
  • 嵌套层级深时,转换代码会变得繁琐

内容的提问来源于stack exchange,提问作者amit

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 12:21:12