做自动化两年,越来越确信:数据问题是自动化稳定性的第一来源,比 UI 变化更频繁、比网络问题更隐蔽。用例挂掉,排查路径经常是"选择器没问题 → 时序没问题 → 数据不对"。这篇讲我们建的"测试数据工厂",把数据从用例里彻底剥离。
一、数据问题的三个典型形态
- 用例间污染:A 用例创建了"测试店铺",B 用例也创建,C 用例的全局列表里出现两个,断言数量直接挂;
- 前置数据缺失:用例假设"有一个带 3 条消息的会话",但环境里这个会话上周被人手动删了——用例挂了,日志却指向 UI;
- 数据规模失真:列表页用例永远只跑 3 条数据,线上 3000 条时的分页、懒加载、性能问题全测不到。
三个形态的共同点:用例自己造数据、清数据,造的方式散落各处,没人知道环境里此刻有哪些数据。
二、数据工厂的核心模型:Profile + Factory + Cleanup
1 | # 数据声明(YAML,和用例分离) |
1 | # 用例里只声明依赖,不写构造代码 |
设计要点:
- Profile 是数据契约:用例声明"我要什么数据"(名字 + 参数),不关心怎么造。数据构造逻辑变更(接口改版)只改 Profile,用例零改动;
- build/teardown 对称:每个构造步骤必须有对应清理,工厂强制校验——不对称的 Profile 不许入库;
- 数据对象带元数据:
conv.id / conv.msg_count / conv.created_at全部结构化,用例断言引用的是数据对象的真实值,永远不写死 "3 条消息"这种字面量。
三、隔离:命名空间 + 租约
多组用例并发跑(分布式执行机场景)时,数据必须互相看不见:
1 | class DataFactory: |
- 命名空间前缀是隔离的基本盘:所有实体名带
run_id,用例之间、批次之间物理隔离,全局列表页也不会互相污染; - 租约回收兜底清理失败:teardown 没跑完(崩溃/取消)的命名空间,后台任务按租约过期强制回收——数据泄漏从"积累到出问题"变成"最多存活 30 分钟";
- 隔离的代价是数据变多,所以工厂同时提供共享池:只读型大数据集(3000 条列表、10 万条用户)按版本预生成、全命名空间共享,只有"会被用例修改"的数据才走隔离。
四、数据规模:Profile 参数化出"压力档"
"数据规模失真"的解法是把规模变成 Profile 参数,CI 分档跑:
1 | # data/profiles/order_list.yaml |
1 | # CI 配置 |
大规模数据只在发版前跑是成本与收益的平衡:日常 CI 用 20 条验证逻辑,发版回归用 3000 条验证分页/懒加载/性能。数据规模第一次成了 CI 配置里的显式参数,而不是"环境里恰好有多少"。
五、落地效果
| 指标 | 数据工厂前 | 后 |
|---|---|---|
| 用例失败中"数据原因"占比 | ~40% | <8% |
| 环境数据泄漏清理 | 人工,每周 1 次 | 租约自动,零人工 |
| 新增用例的数据准备时间 | 0.5~2 小时(手工造数据) | 声明 Profile,分钟级 |
| 跨用例污染类 bug | 偶发难查 | 命名空间隔离后归零 |
六、小结
数据工厂的本质是把"数据"从用例的执行逻辑里提升为一等公民:有契约(Profile)、有生命周期(build/teardown/租约)、有隔离(命名空间)、有规模参数。用例从此只表达"业务断言",数据问题不再污染测试结论——这是所有测试平台里投入产出比最高的基础设施。