Python pytest中Mock被函数赋值的全局变量以避免函数执行
解决pytest中mock全局变量赋值函数仍被执行的问题
问题原因
你当前的写法里,测试文件导入app.file2.VAR1时,Python会先执行file2.py的全部代码——也就是调用some_func()给VAR1赋值,这一步发生在@mock.patch生效之前。所以哪怕后面patch了VAR1,原函数some_func早已经被执行过了。
解决方案
核心思路是:在file2.py被导入执行前,先mock掉它依赖的some_func,这样VAR1赋值时调用的是mock后的函数,原函数根本不会被触发。
方法1:在测试函数内延迟导入file2
把from app.file2 import VAR1放到被patch装饰的测试函数内部,确保mock生效后再导入模块:
from unittest import mock import pytest @mock.patch('app.file2.some_func', return_value="mock的全局变量值") def test_file_2_func(mock_some_func): # 此时mock已经生效,导入file2时会用mock后的函数赋值VAR1 from app.file2 import VAR1 print('made it to my test :)') print(VAR1) # 输出"mock的全局变量值" # 还可以验证mock函数是否被调用 assert mock_some_func.called
方法2:用fixture提前mock并控制导入时机
如果多个测试用例都需要这个mock,可以用pytest fixture来封装:
import pytest from unittest import mock @pytest.fixture def mock_file2_some_func(): # 进入fixture时patch,退出时自动还原 with mock.patch('app.file2.some_func', return_value="mock值"): yield def test_file_2(mock_file2_some_func): # 在fixture的mock生效后再导入 from app.file2 import VAR1 assert VAR1 == "mock值"
方法3:重新加载模块(适合已提前导入的场景)
如果测试文件已经提前导入了app.file2,可以先patch,再用importlib.reload重新加载模块,让模块重新执行赋值逻辑:
from unittest import mock import pytest import importlib import app.file2 # 提前导入了模块 @mock.patch('app.file2.some_func', return_value="重新加载后的mock值") def test_file_2_reload(mock_some_func): # 重新加载模块,此时会用mock后的函数赋值VAR1 importlib.reload(app.file2) print(app.file2.VAR1) # 输出"重新加载后的mock值"
关键注意点
- mock的目标必须是**
file2.py里引用的some_func**(即app.file2.some_func),而不是file1.py里的原函数,这是Python mock的"where it is used"原则。 - 一定要确保mock在
file2模块执行前生效,否则原函数必然会被调用。
内容的提问来源于stack exchange,提问作者dataviews
相关产品推荐
相关产品推荐

