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

如何通过pytest monkeypatch装饰Stub而非完全替换原函数?

问题:如何用pytest monkeypatch给原函数添加装饰逻辑(保留原执行)?

我有如下示例代码:

import pytest

class Helper:
    def function1(self):
        print("helper function called")

class SUT:
    def real_function(self):
        helper = Helper()
        helper.function1()
        print("real function called")

def test_Test(monkeypatch):
    test = SUT()
    def stub_function1(self):
        print("helper is stubbed")

    monkeypatch.setattr(Helper, "function1", stub_function1)
    test.real_function()

运行pytest .\test_scratch_1.py --capture=tee-sys后,按预期输出helper is stubbed和real function called。

但我希望先输出helper function called,再输出helper is stubbed——也就是不完全替换原函数,而是给函数添加后续执行的装饰逻辑。我尝试了以下写法:

import pytest

class Helper:
    def function1(self):
        print("helper function called")

class SUT:
    def real_function(self):
        print("real function called")

def test_Test(monkeypatch):
    test = SUT()
    helper_original = Helper()
    def stub_function1(helper_original_not_stubbed):
        helper_original_not_stubbed.function1()
        print("helper is stubbed")

    monkeypatch.setattr(Helper, "function1", stub_function1(helper_original))
    test.real_function()

但结果和之前一致,请问该如何实现我的需求?


解决方案

你之前的写法错在:stub_function1(helper_original)是直接调用了这个函数,把调用结果(而非函数本身)赋值给了Helper.function1,自然达不到预期效果。正确的做法是先保存原类方法的引用,再定义一个包装函数,在包装函数里先执行原逻辑,再新增自定义逻辑,最后用monkeypatch替换原方法。

修改后的测试代码如下:

import pytest

class Helper:
    def function1(self):
        print("helper function called")

class SUT:
    def real_function(self):
        helper = Helper()
        helper.function1()
        print("real function called")

def test_Test(monkeypatch):
    test = SUT()
    # 保存原类方法的引用
    original_func = Helper.function1

    # 定义包装函数,保留原方法的self参数,先执行原逻辑再执行新增逻辑
    def wrapped_func(self):
        original_func(self)
        print("helper is stubbed")

    # 替换Helper类的function1为包装函数
    monkeypatch.setattr(Helper, "function1", wrapped_func)
    test.real_function()

运行后会得到预期输出:

helper function called
helper is stubbed
real function called

核心要点

  • 必须保存原类方法的引用,而非实例方法,因为SUT中会新建Helper实例调用方法
  • 包装函数要保留原方法的参数(这里是self),保证调用时的上下文正确
  • 给monkeypatch赋值时,要传入包装函数本身,不能传入函数调用后的结果

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 23:55:16