如何在Hypothesis状态测试中使用Syrupy创建并对比快照?
在Hypothesis状态测试中使用Syrupy快照
因为Hypothesis的RuleBasedStateMachine不支持pytest夹具,没法直接用Syrupy的snapshot夹具,核心解决思路是手动初始化Syrupy的SnapshotAssertion实例,绕过夹具限制,同时保留快照对比/更新的功能。
核心实现步骤
- 手动初始化Syrupy快照:在状态机类的初始化方法里创建
SnapshotAssertion实例,指定快照存储路径和更新逻辑。 - 统一更新控制:通过pytest命令行参数
--snapshot-update控制快照的更新/对比模式,和常规Syrupy用法保持一致。 - 唯一快照标识:状态机生成的测试序列是动态的,要给每个快照设置唯一名称(比如动作序列、状态阶段),避免不同用例的快照相互覆盖。
完整代码示例
首先安装依赖:
pip install hypothesis syrupy
测试文件test_state_machine.py:
from hypothesis.stateful import RuleBasedStateMachine, rule, initialize from syrupy.extensions.single_file import SingleFileSnapshotExtension from syrupy import SnapshotAssertion import pytest class ExampleStateMachine(RuleBasedStateMachine): def __init__(self): super().__init__() # 手动初始化Syrupy快照 self.snapshot = SnapshotAssertion( extension=SingleFileSnapshotExtension, test_location=__file__, # 以当前测试文件为快照定位基准 update_snapshots=pytest.config.getoption("--snapshot-update", default=False) ) self.data = [] self.action_log = [] # 记录动作序列,用于生成唯一快照ID @initialize def setup_initial_state(self): self.data = [] self.action_log = [] @rule(value=int) def add_value(self, value): self.data.append(value) self.action_log.append(f"add({value})") # 用动作序列作为快照名称,确保每个测试序列的快照唯一 snapshot_id = "_".join(self.action_log) self.snapshot.assert_match(self.data, name=snapshot_id) @rule() def verify_final_state(self): # 对最终状态单独生成快照 final_snapshot_id = "final_state_" + "_".join(self.action_log) self.snapshot.assert_match(self.data, name=final_snapshot_id) # 生成测试用例类,设置固定seed保证测试确定性 TestExampleStateMachine = ExampleStateMachine.TestCase.with_settings(seed=12345)
运行方式
- 首次运行/更新快照:生成或更新快照文件
pytest test_state_machine.py --snapshot-update - 常规快照对比:自动对比现有快照,检查状态变更是否符合预期
pytest test_state_machine.py
关键注意事项
- 固定Hypothesis的
seed参数可以保证测试序列的确定性,避免每次运行生成不同的快照。 - 快照名称必须唯一,否则不同的测试序列会覆盖同一个快照文件,导致断言失败。
- 不需要每个动作都做快照时,可以只在关键节点(比如初始化后、最终状态)进行快照断言。
内容的提问来源于stack exchange,提问作者Yang Bo
相关产品推荐
相关产品推荐

