3、安装与引入unittest.mock库:Python标准库介绍

unittest.mock 是 Python 标准库的一部分。没错,从 Python 3.3 开始它就内置了。

我刚开始写测试时,以为要 pip install mock,折腾了半天……后来才发现,原来早就装好了。

这一节咱们就把它捋清楚:怎么引入、有什么注意事项、怎么验证。

3.1 它到底在哪?

unittest.mock 位于 Python 的标准库套件中,属于 unittest 模块的子模块。你不需要额外安装任何包。

简单来说:

  • Python 3.3+:直接用 from unittest.mock import ...
  • Python 2.x / 3.2 及更低:需要 pip install mock,然后 from mock import ...
  • Python 3.x 最新版(3.8+):依然保持标准库状态,并且增加了不少实用特性

重要结论:如果你在用 Python 3.3 及以上,不需要装任何东西。直接引入即可。

3.2 如何引入?常见写法

我个人习惯这样写:

from unittest.mock import Mock, MagicMock, patch, PropertyMock

这就够了。你可能会问:为什么要同时引入 Mock 和 MagicMock?

嗯,简单回答:MagicMock 是 Mock 的子类,它自动帮你实现了 __len__、__iter__ 等魔术方法。大部分场景用 MagicMock 更省事。

如果你只需要一个简单的替身对象,也经常这么写:

from unittest.mock import Mock
m = Mock()
m.some_method.return_value = 42

还有一种常见的写法:

import unittest.mock
# 然后通过 unittest.mock.Mock 访问

但这样的代码会显得啰嗦。我建议用 from ... import 的方式,更清爽。

3.3 版本差异:小心这个坑

我曾经在写一个跨 Python 2 和 3 的项目时,直接用了 from unittest.mock import patch,结果在 Python 2 的 CI 上直接报 ImportError。排查半天才发现是版本兼容问题。

解决方案很简单:

  • 如果只支持 Python 3.3+,直接 from unittest.mock import ...
  • 如果需要兼容 Python 2 / 3.2 以下,用 mock 第三方库,并统一引入方式:
try:
    from unittest.mock import Mock, patch
except ImportError:
    from mock import Mock, patch

另外,Python 3.5 之前 AsyncMock 还不存在(AsyncMock 是 3.8 加入的)。如果你要 mock 异步代码,注意版本。

⚠️ 版本注意:AsyncMock 在 Python 3.8+ 才可用。Python 3.7 及以下需要手动 mock 协程或使用第三方库。

3.4 验证是否已安装

打开终端,输入一行命令就能确认:

python -c "from unittest.mock import Mock; print('OK')"

如果不报错,输出 OK,那就说明一切正常。

如果你用的是老旧 Python(比如 2.7 或 3.2),想要用 mock 标准库,那只能升级 Python 了。或者安装第三方包:

pip install mock

然后改用 from mock import Mock。

3.5 引入后能做什么?——核心对象一览

下面这张表展示了我最常用的几个对象,以及它们各自的用途:

对象用途什么时候用
Mock基础替身对象大部分场景的默认选择
MagicMock带魔术方法的替身需要支持 len()、iter() 等操作时
patch上下文管理器 / 装饰器,临时替换目标对象需要替换外部依赖时(推荐方式)
PropertyMock模拟属性(property)替身需要返回动态属性值
AsyncMock模拟异步函数Python 3.8+,测试 async 代码

你想想看,这五个对象几乎覆盖了 95% 的 mock 需求。后面章节我会详细摆弄它们。

3.6 本章知识结构

下面这张图帮你理清 unittest.mock 的定位和脉络:

unittest.mock 知识结构 unittest.mock 标准库 引入方式:unittest.mock → 或 mock 第三方(低版本兼容) Mock / MagicMock patch 上下文管理器 AsyncMock(3.8+) return_value / side_effect PropertyMock 模拟属性 assert_called_with 验证 引入后直接用,不需要 pip install Python 3.8+ 可完整使用 AsyncMock 低版本(Python 2 / 3.2)需 pip install mock

3.7 避坑指南 & 个人建议

  • 不要混用引入路径:一会 from unittest.mock import Mock,一会 from mock import Mock,同一个测试文件里会报错。统一引入写法。
  • 注意 modules 替换:如果你用 patch 时引入路径写错了(比如漏了完整包名),替身根本不会生效。我踩过这个坑:patch('os.path.exists') 写成了 patch('path.exists'),排查了很久。
  • Mock 对象不是万能的:它只能替换你显式指定的调用。如果外部代码通过 __import__ 动态导入,patch 可能覆盖不到。记得先测一下。

💡 小技巧:写完测试后,运行 python -m pytest --tb=short,如果遇到 ModuleNotFoundError: No module named 'unittest.mock',那表明你的 Python 版本低于 3.3。别慌,用 pip install mock 然后改导入方式就好了。