Python测试辅助工具:unittest.mock

当然可以!下面是对 Python 中 unittest.mock(简称 Mock 模块)的详细使用方式和示例介绍,适合用于模拟函数、方法、对象、类、接口请求、数据库等外部依赖。



📦 一、什么是 Mock?

Mock 是一个测试辅助工具,用于 模拟某个对象或函数的行为,以便在单元测试中避免调用真实依赖(如数据库、文件系统、网络请求等),达到测试隔离的目的。

Mock 属于 unittest.mock 模块,Python 3.3+ 已内置。


🧰 二、常用的 Mock 工具

工具名功能说明
Mock创建一个可定制的模拟对象
MagicMockMock 的子类,支持魔法方法(如 __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)