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

调整Python Mock顺序时断言异常:含导入依赖的函数Mock问题

问题根源:Patch触发模块导入的时机与顺序冲突

你遇到的问题核心在于**patch装饰器触发模块导入的时机**,以及Python导入机制中引用的不可变性:

当使用@patch("module1.func1b")时,如果module1尚未被导入,patch会自动导入该模块。此时module1的顶层代码会执行from module2 import func2a,将module2.func2a的原始函数引用存入module1的命名空间。

调换patch顺序后,执行流程变成:

  1. 先执行@patch("module1.func1b"),触发module1导入,此时module1拿到的是func2a的原始实现;
  2. 再执行@patch("module2.func2a"),仅替换module2中的func2a,但module1里已缓存的func2a引用不会同步更新;
  3. 调用func1a时,实际执行的是原始的func2a(不会触发mock),只有func1b的mock被调用,导致mock_manager.mock_calls仅包含call.mock_func1b(),与预期的两个调用不匹配,触发断言错误。

而原测试代码能正常运行的原因是:

  • 先执行@patch("module2.func2a"),替换module2中的func2a为mock;
  • 再执行@patch("module1.func1b"),触发module1导入,此时module1从module2拿到的是已经被mock后的func2a,调用func1a时两个mock都会被触发。

解决方案

有两种可靠的解决方式:

1. 修正patch目标,直接mock模块内的引用

由于module1已经通过from module2 import func2a将func2a导入自身命名空间,正确的mock目标应该是module1.func2a,而非module2.func2a。这样无论patch顺序如何,都能直接替换module1里实际使用的func2a引用:

from unittest.mock import MagicMock, Mock, call, patch
import pytest

@patch("module1.func1b")
@patch("module1.func2a")  # 修改为mock module1内的func2a引用
def test_func1a(
    mock_func2a: MagicMock,
    mock_func1b: MagicMock,
)->None:
    from module1 import func1a
    mocks = ( mock_func2a,
              mock_func1b,
    )
    mock_manager = Mock()
    for mock in mocks:
        mock_manager.attach_mock(mock, "mock_" + mock._extract_mock_name())

    expected_calls = [
        call.mock_func2a(),
        call.mock_func1b(),
    ]
    func1a()
    assert mock_manager.mock_calls == expected_calls

2. 保持正确的patch顺序

如果坚持mockmodule2.func2a,需要确保先patch被依赖的模块,再patch当前模块(装饰器写法上,将先生效的patch放在下方):

# 保持原patch顺序:先patch module2.func2a(下方装饰器),再patch module1.func1b(上方装饰器)
@patch("module1.func1b")
@patch("module2.func2a")
def test_func1a(mock_func2a: MagicMock, mock_func1b: MagicMock):
    from module1 import func1a
    # 后续代码不变

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 05:55:53