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

测试函数上方使用@patch与函数内使用with patch的差异

@patch装饰器与with patch语句的核心区别

1. 作用范围不一样

  • @patch装饰器:从测试函数开始执行前就完成patch,覆盖整个测试函数的生命周期,函数执行完自动撤销patch。
  • with patch语句:只在with包裹的代码块内生效,进入块时patch,退出块(哪怕抛异常)立刻撤销。

2. 作用域与mock覆盖逻辑有差异

  • @patch装饰器:需要把mock对象作为参数传入测试函数,整个函数内都能调用这个mock。但如果函数内部又用with patch处理同一个路径,会直接覆盖装饰器创建的mock——这就是你遇到装饰器不生效的原因:内部的with语句重新patch了my_path,把装饰器的设置(比如return_value=None)给覆盖了。
  • with patch语句:mock通过as绑定成局部变量,只在with块内有效,块外还是用原对象(或装饰器创建的mock,如果同时用了装饰器的话)。

3. 适用场景不同

  • 要是整个测试函数都需要patch同一个对象,用@patch装饰器更简洁,不用嵌套代码块。
  • 要是只有测试里的部分代码需要patch,或者需要在函数内多次切换同一个对象的mock状态,用with patch更灵活。

针对你问题的修复示例

你的代码里装饰器被内部with语句覆盖了,要让装饰器生效,删掉内部的with patch,直接用传入的mock参数就行:

@patch(
    "my_path",
    return_value=None,
)
def test_function_to_test(mock_):
    # 直接使用装饰器创建的mock对象
    instance = MyClass("a", "b")
    instance.function_to_test()
    # 可以断言mock的调用情况
    mock_.assert_called_once()

如果确实需要临时patch,注意避免作用域冲突:

@patch("my_path", return_value=None)
def test_function_to_test(mock_decorator):
    # 这里用的是装饰器的mock
    print(mock_decorator.return_value)  # 输出None
    
    # 临时用新mock覆盖,仅在with块内生效
    with patch("my_path", return_value="temp") as mock_with:
        print(mock_with.return_value)  # 输出"temp"
    
    # 退出with块后,回到装饰器的mock
    print(mock_decorator.return_value)  # 输出None

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 04:00:00