Python测试辅助工具:unittest.mock
已于 2025年07月20日 13:01 修改
访问次数:0
当然可以!下面是对 Python 中 unittest.mock(简称 Mock 模块)的详细使用方式和示例介绍,适合用于模拟函数、方法、对象、类、接口请求、数据库等外部依赖。
📦 一、什么是 Mock?
Mock 是一个测试辅助工具,用于 模拟某个对象或函数的行为,以便在单元测试中避免调用真实依赖(如数据库、文件系统、网络请求等),达到测试隔离的目的。
Mock 属于 unittest.mock 模块,Python 3.3+ 已内置。
🧰 二、常用的 Mock 工具
| 工具名 | 功能说明 |
|---|---|
Mock | 创建一个可定制的模拟对象 |
MagicMock | 是 Mock 的子类,支持魔法方法(如 __len__) |
patch | 动态替换模块或类中的对象 |
patch.object | 替换对象上的属性 |
patch.dict | 替换字典内容 |
🔧 三、Mock 使用方式详解
✅ 1. Mock 简单用法
from unittest.mock import Mock
mock_func = Mock()
mock_func.return_value = 123
print(mock_func()) # 输出 123
mock_func.assert_called_once() # 验证是否被调用
✅ 2. 设置不同返回值
mock_func = Mock()
mock_func.side_effect = [1, 2, 3]
print(mock_func()) # 1
print(mock_func()) # 2
print(mock_func()) # 3
还可以抛出异常:
mock_func.side_effect = ValueError("Oops!")
mock_func() # 抛出 ValueError
✅ 3. 使用 patch 替换函数或对象
📌 场景:你不想真的发 HTTP 请求
# weather.py
import requests
def get_weather(city):
return requests.get(f"https://weather.api/{city}").json()
✅ 测试代码中 mock requests.get
# test_weather.py
import unittest
from unittest.mock import patch
from weather import get_weather
class TestWeather(unittest.TestCase):
@patch('weather.requests.get') # 替换 weather 模块中的 requests.get
def test_get_weather(self, mock_get):
mock_get.return_value.json.return_value = {'temp': 28}
result = get_weather("beijing")
self.assertEqual(result['temp'], 28)
mock_get.assert_called_once_with("https://weather.api/beijing")
if __name__ == '__main__':
unittest.main()
✅ 4. 使用 patch.object 替换类方法或属性
class Database:
def connect(self):
return "Real Connection"
db = Database()
with patch.object(Database, 'connect', return_value="Mocked Connection"):
print(db.connect()) # 输出:Mocked Connection
✅ 5. 使用 MagicMock 模拟特殊方法
from unittest.mock import MagicMock
mock_list = MagicMock()
mock_list.__len__.return_value = 10
print(len(mock_list)) # 输出 10
✅ 6. 使用 patch.dict 模拟环境变量或配置项
import os
from unittest.mock import patch
def get_env():
return os.environ.get("ENV")
with patch.dict(os.environ, {"ENV": "test"}):
print(get_env()) # 输出 "test"
🔍 四、Mock 验证方法调用
| 方法 | 说明 |
|---|---|
assert_called() | 验证是否调用过一次 |
assert_called_once() | 验证是否调用过且只调用一次 |
assert_called_with(*args) | 验证调用时传入的参数 |
assert_any_call(*args) | 是否至少一次以指定参数调用 |
assert_has_calls([call(), ...]) | 按顺序匹配多次调用 |
reset_mock() | 重置调用记录 |
示例:
mock_func = Mock()
mock_func(10)
mock_func.assert_called_with(10)
mock_func.assert_called_once()
✅ 五、完整例子:模拟文件读取
# file_reader.py
def read_file(path):
with open(path, 'r') as f:
return f.read()
测试时不想访问真实文件系统:
import unittest
from unittest.mock import mock_open, patch
from file_reader import read_file
class TestFileReader(unittest.TestCase):
def test_read_file(self):
mock_data = "hello world"
with patch("builtins.open", mock_open(read_data=mock_data)):
result = read_file("fake.txt")
self.assertEqual(result, "hello world")
🧠 六、总结
| 使用场景 | 推荐用法 |
|---|---|
| 替换函数/模块 | @patch() |
| 替换类的方法/属性 | patch.object() |
| 替换字典(如配置、环境) | patch.dict() |
| 模拟对象行为 | Mock() / MagicMock() |
如果你有特定的使用场景(如:模拟数据库、模拟类之间依赖、网络请求等),我可以给出更贴近实战的例子。是否有你具体想 mock 的对象或系统?
评论(0)