如何用Pytest Patch Mock全局变量并避免调用外部服务器函数
解决Pytest中全局变量依赖外部函数的测试问题
问题核心
你的测试代码之所以失败,是因为模块导入阶段就自动执行了server_function_1()。当你在测试文件里写import my_module时,global_result_of_server_func已经被真实函数赋值(甚至直接报错),后续的patch操作根本无法回溯修改这个已经初始化完成的全局变量。
可行解决方案
方案一:在模块导入前完成函数Patch
修改测试逻辑,先mock目标函数,再导入模块,让模块初始化时调用的是mock后的函数。
修改后的test_my_module.py代码:
import pytest from unittest import mock import datetime import logging import sys logger = logging.getLogger(__name__) logging.basicConfig(stream=sys.stdout, level=logging.DEBUG) frozen_time = datetime.datetime(year=2022, month=6, day=1, hour=1, minute=0, second=0, microsecond=0) mock_server_str = "Mock Server String" class TestMyModule(): def test_handler(self): # 先patch目标函数,再导入模块 with mock.patch("my_module.server_function_1", return_value=mock_server_str): import my_module # 再patch时间函数 with mock.patch("my_module.get_current_datetime_str", return_value=frozen_time.strftime('%Y%m%d.%H%M%S.%f')): test_server_val, test_frozen_time = my_module.some_function() assert test_frozen_time == frozen_time.strftime('%Y%m%d.%H%M%S.%f') assert test_server_val == mock_server_str
方案二:重构原模块,延迟全局变量初始化
如果允许修改原模块,将全局变量的初始化逻辑封装到函数中,避免模块导入时自动执行。
修改后的my_module.py:
import datetime def server_function_1(): try: return_val = "Assume the external server function returns a string" except Exception as e: print("Failed") print(e) raise e else: return return_val finally: raise Exception("Cannot connect to server") # 封装全局变量初始化逻辑 def init_global(): global global_result_of_server_func global_result_of_server_func = server_function_1() # 保留正常使用时的自动初始化行为 init_global() def get_current_datetime_str(): return datetime.datetime.now().strftime('%Y%m%d.%H%M%S.%f') def some_function(): return global_result_of_server_func, get_current_datetime_str()
对应的测试文件写法:
import pytest from unittest import mock import datetime import logging import sys logger = logging.getLogger(__name__) logging.basicConfig(stream=sys.stdout, level=logging.DEBUG) frozen_time = datetime.datetime(year=2022, month=6, day=1, hour=1, minute=0, second=0, microsecond=0) mock_server_str = "Mock Server String" # 导入前patch,避免初始化时调用真实函数 with mock.patch("my_module.server_function_1", return_value=mock_server_str): import my_module class TestMyModule(): def test_handler(self): with mock.patch("my_module.get_current_datetime_str", return_value=frozen_time.strftime('%Y%m%d.%H%M%S.%f')): test_server_val, test_frozen_time = my_module.some_function() assert test_frozen_time == frozen_time.strftime('%Y%m%d.%H%M%S.%f') assert test_server_val == mock_server_str
内容的提问来源于stack exchange,提问作者Kevin Tianyu Xu
相关产品推荐
相关产品推荐

