调整Python Mock顺序时断言异常:含导入依赖的函数Mock问题
问题根源:Patch触发模块导入的时机与顺序冲突
你遇到的问题核心在于**patch装饰器触发模块导入的时机**,以及Python导入机制中引用的不可变性:
当使用@patch("module1.func1b")时,如果module1尚未被导入,patch会自动导入该模块。此时module1的顶层代码会执行from module2 import func2a,将module2.func2a的原始函数引用存入module1的命名空间。
调换patch顺序后,执行流程变成:
- 先执行
@patch("module1.func1b"),触发module1导入,此时module1拿到的是func2a的原始实现; - 再执行
@patch("module2.func2a"),仅替换module2中的func2a,但module1里已缓存的func2a引用不会同步更新; - 调用
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
相关产品推荐
相关产品推荐

