Python中模拟加载时变量 解决Flask单元测试logger mock失效问题
问题根源
你遇到的问题由两个核心原因导致:
- patch未激活:你声明的
mock.patch对象没有启动,没有使用上下文管理器或者start()方法触发mock规则,patch本身就没有生效 - 模块加载顺序错误:当你在测试代码中导入
app_demo.app模块时,模块顶层的logs.init_logging()、logger = logging.getLogger(__name__)已经执行完成,此时再patchlogging.getLogger已经无法替换已经赋值给app.logger变量的原生logger对象
修复方案
方案1:直接patch app模块中已实例化的logger(推荐,写法最简单)
直接替换app模块内已经存在的logger变量和logs对象,不需要调整原有业务代码:
# /my_project/tests/test_app.py import pytest from unittest import mock # 先导入app模块,此时logger已完成初始化 from app_demo.app import app @pytest.fixture def client(): app.config['TESTING'] = True with app.test_client() as client: yield client def test_greet(client): # 直接patch app模块里已存在的logger和logs对象 with mock.patch("app_demo.app.logger") as logger_mock, \ mock.patch("app_demo.app.logs") as logs_mock: # 注意请求路径要填写完整路由 resp = client.get("/greet/George") assert resp.status_code == 200 assert resp.data.decode() == "Hello, George!" # 验证调用逻辑 logs_mock.init_logging.assert_called_once() logger_mock.info.assert_called_once_with("George wants a greeting")
方案2:导入app模块前完成patch(适合需要验证logger初始化参数的场景)
如果需要验证logging.getLogger的调用参数,可以在导入app之前就启动patch:
# /my_project/tests/test_app.py import pytest from unittest import mock import sys def test_greet(): # 先启动patch再导入app with mock.patch("app_demo.app.logs.init_logging") as logs_init_mock, \ mock.patch("app_demo.app.logging.getLogger") as get_logger_mock: # 导入app时模块顶层代码调用的就是mock对象 from app_demo.app import app # 验证初始化逻辑 logs_init_mock.assert_called_once() get_logger_mock.assert_called_once_with("app_demo.app") # 启动测试客户端发请求 app.config['TESTING'] = True with app.test_client() as client: resp = client.get("/greet/George") assert resp.data.decode() == "Hello, George!" # 验证info方法调用 get_logger_mock.return_value.info.assert_called_once_with("George wants a greeting") # 测试结束后清除app模块缓存,避免影响其他测试 del sys.modules["app_demo.app"]
注意事项
- 原测试代码中
client.get("George")路径错误,必须填写完整路由路径/greet/George - 方案2如果要封装为fixture使用,需要设置
scope="function",保证每个测试都重新加载app模块
内容的提问来源于stack exchange,提问作者dfashimpaur
相关产品推荐
相关产品推荐

