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

如何Mock字典子类的__setitem__?单元测试无法验证调用

问题根源

当你执行t["a"] = 1这种下标赋值操作时,Python的底层逻辑是直接调用type(t).__setitem__(t, "a", 1)——也就是从类层面查找__setitem__方法,完全不会去读取实例上的__setitem__属性。这就是为什么你在实例上patch或赋值的Mock对象根本没被触发,断言自然失败。

解决方案

方案1:Patch类的__setitem__方法

既然Python是从类里找特殊方法,那直接针对类进行patch即可:

from unittest import mock
from unittest.mock import MagicMock

class MyDict(dict):
    def __setitem__(self, key, value):
        super().__setitem__(key, value)

class TestAssumptions:
    def test_setitem_called(self):
        # 直接patch MyDict类的__setitem__方法
        with mock.patch.object(MyDict, "__setitem__", new=MagicMock(wraps=MyDict.__setitem__)) as setitem:
            t = MyDict()
            t["a"] = 1
            # 注意断言时要传入实例、key、value三个参数
            setitem.assert_called_once_with(t, "a", 1)

方案2:用计数器替代Mock(适合对比子类行为)

如果你的核心需求是验证__setitem__是否被调用、调用次数,完全可以不用Mock,直接在子类里加个计数器:

from collections import UserDict

class MyDict(dict):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setitem_call_count = 0

    def __setitem__(self, key, value):
        self.setitem_call_count += 1
        super().__setitem__(key, value)

class MyUserDict(UserDict):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setitem_call_count = 0

    def __setitem__(self, key, value):
        self.setitem_call_count += 1
        super().__setitem__(key, value)

class TestAssumptions:
    def test_dict_subclass(self):
        t = MyDict()
        t["a"] = 1
        t["b"] = 2
        assert t.setitem_call_count == 2

    def test_userdict_subclass(self):
        t = MyUserDict()
        t["x"] = 10
        assert t.setitem_call_count == 1

这种方式更直观,也方便你对比dict和UserDict子类的行为差异。

方案3:使用纯Python实现的字典包装类

collections.UserDict是纯Python写的字典包装类,它的特殊方法逻辑和内置dict不同——它的__setitem__是通过组合内部的self.data字典实现的,没有内置类型的底层优化限制。不过即使如此,Python调用特殊方法还是会走类层面,所以如果用Mock的话,依然需要patch类的__setitem__,但它的行为更贴近普通Python类,调试起来更方便。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 07:05:00