为何unittest.mock的patch()在multiprocessing子进程中不生效?
unittest.mock.patch在multiprocessing子进程中失效的问题解决
问题原因
multiprocessing的启动方式(fork/spawn)导致mock状态无法跨进程传递:
fork:Unix/Linux默认启动方式,子进程会完整复制父进程的内存空间,包括已生效的mock,因此patch能在子进程中正常工作。spawn:macOS(Python3.8+)、Windows默认启动方式,子进程会重新启动Python解释器并重新导入所有模块,父进程中设置的patch不会被继承,因此子进程调用的是原始函数逻辑。
你的本地环境大概率使用spawn启动方式,而CI环境用的是fork,这就是两者行为差异的核心原因。
解决方案
方案1:强制使用fork启动方式(仅Unix/Linux/macOS可用)
修改主进程中创建上下文的代码,指定用fork方式启动子进程:
def main(): with patch("b.function_to_mock"): # 强制使用fork上下文 context = multiprocessing.get_context('fork') process = context.Process(target=run_new_process, args=()) print("call from the main process") call_mocked_function() process.start() process.join()
这种方式下子进程会直接继承父进程的mock状态,无需修改其他代码即可达到预期效果。
方案2:在子进程内部执行patch
针对spawn启动方式,直接在子进程的目标函数中完成patch操作:
修改b.py中的run_new_process函数:
def run_new_process(): from unittest.mock import patch with patch("b.function_to_mock"): print("call from the subprocess") function_to_mock()
这样不管启动方式是什么,子进程执行时都会先patch目标函数,避免触发真实逻辑。
方案3:用initializer全局初始化patch
在主进程中定义初始化函数,让子进程启动时自动执行patch:
# 在a.py中添加初始化函数 def init_subprocess(): from unittest.mock import patch # 启动全局patch,在子进程生命周期内持续有效 patcher = patch("b.function_to_mock") patcher.start() def main(): with patch("b.function_to_mock"): context = multiprocessing.get_context(multiprocessing.get_start_method()) # 指定子进程初始化函数 process = context.Process(target=run_new_process, args=(), initializer=init_subprocess) print("call from the main process") call_mocked_function() process.start() process.join()
这种方式适合需要在子进程多个函数中复用mock的场景。
验证效果
修改后运行a.py,输出会符合预期:
call from the main process call from the subprocess
内容的提问来源于stack exchange,提问作者Danio
相关产品推荐
相关产品推荐

