UserDict在unittest中不被视为字典

5 投票
3 回答
2319 浏览
提问于 2025-04-18 08:49
import unittest
from UserDict import UserDict

class MyDict(UserDict):
    def __init__(self, x):
        UserDict.__init__(self, x=x)

class Test(unittest.TestCase):
    def test_dict(self):
        m = MyDict(42)
        assert {'x': 42} == m # this passes
        self.assertDictEqual({'x': 42}, m) # failure at here

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

我得到了

AssertionError: Second argument is not a dictionary

我应该用内置的 dict 作为基类,而不是 UserDict 吗?

3 个回答

0

来自Python的unittest源代码

def assertDictEqual(self, d1, d2, msg=None):
    self.assertIsInstance(d1, dict, 'First argument is not a dictionary')
    self.assertIsInstance(d2, dict, 'Second argument is not a dictionary')

这两个参数必须是dict类型的实例。

而且不幸的是,UserDict的实例并不是dict的实例。

assert isinstance(m, dict) # this is False

正如文档中提到的,你可以使用m.data来返回一个真正的dict

IterableUserDict.data

A real dictionary used to store the contents of the UserDict class.
0

这个问题是因为 UserDict 实际上并不是一个 dict 对象。它是在很久以前创建的,那时候还不能直接从内置的 dict 类型继承。根据文档

[UserDict] 已经被直接从 dict 继承的能力所取代...

所以我觉得直接从 dict 继承就可以了;我看不出 UserDict 提供了什么额外的功能。


另外,我个人也对 UserDict 有点意见,因为这个模块的名字违反了 PEP8 的规范,这让我觉得很烦。


*其实我八分钟前才知道它的存在。

4

问题在于,assertDictEqual() 这个函数首先会检查传入的两个参数是否都是 dict 类型的对象:

def assertDictEqual(self, d1, d2, msg=None):
    self.assertIsInstance(d1, dict, 'First argument is not a dictionary')
    self.assertIsInstance(d2, dict, 'Second argument is not a dictionary')
    ...

UserDict 并不是 dict 类型的对象:

>>> m = UserDict(x=42)
>>> m
{'x': 42}
>>> isinstance(m, dict)
False

所以,不要直接使用 UserDict 类,而是应该使用它的 data 属性,这个属性里面包含了一个真正的字典:

self.assertDictEqual({'x': 42}, m.data)

或者,正如其他人已经建议的那样,直接使用普通的字典就可以了。

撰写回答