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

使用mock.patch.object时为何能修改未被补丁的属性返回值

你代码里的核心误区在先:@mock.patch.object(PhoneBook, "add")注入到测试函数的mock_phonebook参数,本质是被补丁替换的add方法的Mock对象,根本不是PhoneBook类或其实例的Mock,你把它传给Mobile的构造是完全错误的用法,后续的异常表现都是这个错误+Mock的默认特性叠加的结果。

1 上述表现是否是mock.patch.object的预期行为?

是,属于两个设计特性的正常表现:

  • unittest.mock.Mock默认开启自动创建子属性的特性:只要访问Mock对象不存在的属性/方法,会自动生成新的子Mock对象返回,不会抛出属性不存在的异常。所以你可以给这个add方法的Mock对象随意设置lookup的返回值、做调用断言,都是Mock的正常行为。
  • patch.object只负责替换你指定的属性,不会限制注入的Mock对象的属性访问逻辑。

2 为什么没用到指定的add属性也需要传入?为什么不校验补丁属性的实际使用情况?

  • 你传入add是告诉patch.object你要替换PhoneBook类下的add属性,不管测试过程中用不用,patch都会执行「替换-测试结束后还原」的流程,这个参数是patch执行替换的必填目标,和你后续用不用没关系。
  • patch本身只负责替换和还原的生命周期,不会校验你有没有用到被替换的属性,这是设计如此:很多场景下补丁的作用只是屏蔽原方法的副作用,不需要主动调用或者断言,自然不需要做使用校验。
  • 只有传入不存在的属性会报错,是因为patch执行替换前需要先定位到要替换的目标,找不到目标自然无法执行替换操作,属于替换动作本身的前置校验,和后续使用无关。
  • 补充:你当前的测试逻辑完全没有用到add方法,这个patch的写法本身就是多余的,完全可以删掉。

3 是否错误理解了patch装饰器的使用场景?

是的,你对patch的作用、注入参数的含义都有偏差:

  • patch系列方法的核心作用是:在测试的生命周期内,把你指定位置的目标替换成Mock对象,测试结束后自动还原。你需要替换什么目标就传什么,不需要替换的目标不要随意加patch。
  • 你这个测试场景根本不需要用patch:你只是要给Mobile传入一个模拟的PhoneBook依赖,直接手动创建Mock对象即可,正确写法如下:
from unittest.mock import Mock
import logging

class PhoneBook:
    def __init__(self):
        self.numbers: dict[str, str] = {}

    def add(self, name: str, number: str) -> None:
        self.numbers[name] = number

    def lookup(self, name: str) -> str:
        return self.numbers[name]

class Mobile:
    def __init__(self, phonebook: PhoneBook):
        self.phonebook = phonebook

    def call(self, name: str) -> None:
        number = self.phonebook.lookup(name)
        logging.info(f"Calling {name} on number: {number}")

def test_mobile_call():
    # Arrange
    mock_phonebook = Mock()
    mock_phonebook.lookup.return_value = "123"
    mobile = Mobile(mock_phonebook)
    # Act
    mobile.call("Nick")
    # Assert
    mock_phonebook.lookup.assert_called_with("Nick")

只有当你要替换的目标是代码其他位置隐式导入/实例化的对象,无法手动传入Mock的时候,才需要用到patch。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 05:18:02