Python mock怎么用_测试中模拟对象技巧

10次阅读

Python mock 怎么用_测试中模拟对象技巧

Python 的 mock 主要用于在单元测试中隔离外部依赖,比如数据库、网络请求、第三方 API 或复杂计算逻辑。核心是用可控的“假对象”替代真实对象,让测试专注验证自身逻辑,而不是被外部环境干扰。

patch 临时替换对象(最常用)

当你要模拟模块里某个函数、类或属性时,patch 是首选。它能在测试运行期间动态替换目标,测试结束自动还原,避免污染其他测试。

  • 装饰器写法(推荐,清晰易读):

  from unittest.mock import patch
  import requests

  @patch(‘requests.get’)
  def test_fetch_data(mock_get):
    mock_get.return_value.json.return_value = {‘id’: 1, ‘name’: ‘test’}
    result = fetch_user(1)
    assert result[‘name’] == ‘test’
    mock_get.assert_called_once_with(‘https://api.example.com/users/1’)

  • 上下文管理器写法(适合单个测试块内局部控制):

  with patch(‘builtins.open’, mock_open(read_data=’hello’)) as mock_file:
    content = read_config()
    assert content == ‘hello’

立即学习 Python 免费学习笔记(深入)”;

⚠️ 注意:patch 的路径必须是“被测试代码里导入并使用的位置”,不是定义位置。例如你在 my_module.py 中写了 import requests,然后调用 requests.get(),那就要 @patch('my_module.requests.get') —— 很多人在这里出错。

控制返回值和行为:return_value vs side_effect

return_value 适用于固定返回;side_effect 更灵活,支持抛异常、动态返回、甚至调用真实函数。

  • return_value=42 → 每次调用都返回 42
  • return_value={'status': 'ok'} → 返回字典,可链式调用(如 mock_obj.data.name
  • side_effect=ValueError('timeout') → 调用即抛异常
  • side_effect=[1, 2, 3] → 第一次调用返回 1,第二次 2,第三次 3
  • side_effect=lambda x: x * 2 → 接收参数,返回计算结果

模拟类实例与方法调用

想测试一个类的方法是否被正确调用,或者验证它如何与依赖交互?可以 mock 整个类,再配置它的实例行为。

  from unittest.mock import patch, MagicMock

  @patch(‘my_module.Database’)
  def test_save_user(mock_db_class):
    # mock_db_class() 返回一个 mock 实例
    mock_db = mock_db_class.return_value
    mock_db.save.return_value = True

    result = save_user_to_db({‘name’: ‘Alice’})
    assert result is True
    mock_db.save.assert_called_once_with({‘name’: ‘Alice’})

关键点:mock_db_class.return_value 是对“实例”的模拟,而 mock_db.save 是对“实例方法”的模拟。别混淆 return_value 的层级。

检查调用情况:断言真实发生了什么

光有返回值不够,还要确认你的代码确实按预期调用了依赖。mock 对象自带丰富的断言方法:

  • assert_called() —— 至少调用过一次
  • assert_called_once() —— 精确调用一次
  • assert_called_with(arg1, arg2) —— 最后一次调用的参数匹配
  • assert_has_calls([call(1), call(2)]) —— 检查多次调用的完整顺序
  • call_argscall_args_list —— 获取实际传入的参数(可用于调试)

例如:assert mock_send.call_args_list == [call('hi'), call('bye')] 可精准验证调用序列。

text=ZqhQzanResources