pytest-snapshot已官方归档,pip install默认安装过时的0.5.x版本(仅支持Python旧版本),不再维护,不推荐使用。

pytest-snapshot 本身不维护了,官方已归档,直接 pip install 会失败或装到过时的 0.5.x 版本(仅支持 Python
为什么 pip install pytest-snapshot 失败或测试不运行
PyPI 上的 pytest-snapshot 自 2020 年起停止更新,GitHub 仓库 marked as “archived”。它依赖旧版 py 和硬编码的 pytest 钩子机制,在 pytest ≥ 6.0 和 Python ≥ 3.8 下会抛出 AttributeError: 'Config' object has no attribute 'slaveinput' 或导入失败。
- 你看到的
No module named 'pytest_snapshot'通常是因为安装空包或版本冲突 - 即使装上,
@snapshot装饰器在新 pytest 中根本不会被识别 - 快照文件默认生成在错误路径(如
__snapshots__/test_foo.py.snap),但插件不处理目录自动创建或编码问题
替代方案:用 pytest-asyncio + pytest-snapshot 的精神继承者 —— pytest-snapshot(注意重名)
真正可用的是社区维护的现代分支:pytest-snapshot(作者 erev0s,PyPI 包名相同但版本从 0.7.0+ 起重构)。它兼容 pytest ≥ 7.0、Python 3.8+,API 几乎一致,但必须手动指定安装源:
pip install -U "pytest-snapshot @ git+https://github.com/erev0s/pytest-snapshot.git"
- 安装后,
pytest --snapshot-update可正常生成/更新快照 - 快照默认存放在测试文件同级的
__snapshots__/目录,文件名基于测试函数名自动推导 - 支持 JSON、字符串、字典、列表等常见 Python 类型,底层调用
pprint.pformat确保可读性与稳定性 - 不支持自定义序列化器(比如对 datetime 或 numpy array 做特殊处理),遇到这类对象需先转成 dict/list 或 str
写一个能跑通的快照测试示例
假设你有个函数返回结构化数据,想确保输出格式不意外变更:
立即学习“Python免费学习笔记(深入)”;
def get_user_profile():
return {
"id": 123,
"name": "Alice",
"tags": ["admin", "beta"],
"created_at": "2024-05-20T10:30:00Z" # 注意:避免直接塞 datetime 对象
}对应测试:
def test_get_user_profile(snapshot):
assert get_user_profile() == snapshot-
snapshot是 pytest 自动注入的 fixture,无需 import - 首次运行加
--snapshot-update参数生成__snapshots__/test_example.py.snap - 后续运行会比对当前返回值和快照文件内容(逐行字符串比较),不通过则报 diff
- 如果修改了
get_user_profile返回结构,必须显式加--snapshot-update才能通过,防止无感知变更
容易被忽略的三个细节
快照测试不是“设好就忘”的黑盒 —— 它的可靠性高度依赖人为约定:
- 快照文件是代码的一部分,必须提交进 Git;否则 CI 会因找不到快照而失败
- 不要在快照中包含非确定性字段(如
uuid4()、time.time()、内存地址),否则每次运行都不同;应提前 mock 或剥离 -
snapshotfixture 不支持参数化测试的每个 case 单独快照(比如@pytest.mark.parametrize);若需区分,得手动拼接快照名称:assert result == snapshot(name="test_with_foo")
快照测试的价值不在“省事”,而在“锁定结构契约”——一旦快照变,就得人眼确认:这是预期改进,还是破坏性改动。别让它变成没人敢点 --snapshot-update 的定时炸弹。


















