2022-07-01 14:41:09
mock.patch 是 Python unittest.mock 模块中的核心工具,用于在单元测试中临时替换对象(如函数、类、方法等),通过装饰器或上下文管理器实现测试隔离,并在结束后自动恢复原状。
核心功能与常见用途替换函数返回值
模拟外部依赖(如网络请求、数据库查询)的行为,避免真实调用。
示例:模拟 requests.get() 返回固定响应,测试 fetch_data() 函数:from unittest.mock import patchimport requestsdef fetch_data(): response = requests.get('
关键点:patch 的路径需为被测试代码中实际导入的名称(如 requests.get 而非模块定义位置)。
控制作用范围
装饰器:适用于整个测试函数需替换的场景。@patch('module.ClassName')def test_something(mock_class): pass
上下文管理器(with 语句):仅在代码块内替换。def test_something(): with patch('module.ClassName') as mock_class: pass
模拟类方法与实例方法
类方法:直接替换类上的方法(所有实例共享)。class MyClass: def method(self): return 'real'@patch.object(MyClass, 'method', return_value='mocked')def test_class_method(mock_method): obj = MyClass() assert obj.method() == 'mocked'
实例方法:需先创建实例,再替换实例方法(仅影响该实例)。def test_instance_method(): obj = MyClass() with patch.object(obj, 'method', return_value='mocked_instance'): assert obj.method() == 'mocked_instance'
路径准确性
patch 的路径需为被测试代码中实际导入的模块路径。例如:
若代码中导入为 from my_module import requests,则应 patch 'my_module.requests.get' 而非 'requests.get'。
副作用处理
return_value:固定返回值,适用于简单场景。
side_effect:模拟异常或动态返回值。@patch('requests.get')def test_network_error(mock_get): mock_get.side_effect = Exception('Network error') with pytest.raises(Exception): fetch_data()
嵌套与多对象替换
可同时替换多个对象,通过装饰器叠加或嵌套 with 语句:@patch('module.ClassA')@patch('module.ClassB')def test_multiple_patches(mock_b, mock_a): pass# 或使用上下文管理器def test_multiple_patches(): with patch('module.ClassA') as mock_a, patch('module.ClassB') as mock_b: pass
自动恢复与清理
patch 会在测试结束后自动恢复原对象,无需手动清理,但需确保测试代码未意外修改全局状态。
问题1:Mock 未生效
原因:路径错误或未正确导入被测试对象。
解决:检查 patch 路径是否与被测试代码中的导入路径一致。
问题2:多个调用点需不同返回值
原因:return_value 固定,无法区分调用顺序。
解决:使用 side_effect 返回列表或函数:@patch('requests.get')def test_dynamic_responses(mock_get): mock_get.side_effect = [Mock(status_code=200), Mock(status_code=404)] assert fetch_data() == 200 # 第一次调用 assert fetch_data() == 404 # 第二次调用
问题3:模拟异步函数
原因:异步函数需返回 Coroutine 对象。
解决:使用 AsyncMock(Python 3.8+)或手动创建协程: from unittest.mock import AsyncMock import aiohttp async def fetch_async_data(): async with aiohttp.ClientSession() as session: async with session.get('
路径需准确指向被测试代码中的导入名称。
根据场景选择装饰器或上下文管理器。
灵活使用 return_value 和 side_effect 控制行为。
通过合理使用 mock.patch,可显著提升单元测试的质量和可维护性。