本篇是第 9 章第 4 节,讲质量保障,是把「能跑」变「敢改」的护盾。
我们用三层测试:单元测转换(小样数据跑通、行数符合预期)、集成测作业(端到端跑通、落库正确)、回归测变更(改完重跑历史案例比对)。没有测试的转换,重构时没人敢动,技术债越积越深。
测试数据要可控:准备一份脱敏小样,覆盖正常、边界、脏数据三类。我们把它随仓库提交,CI 用 Pan 跑转换吃这份小样,断言输出行数和非空字段。脏数据能正确分流是重点断言项。
数据质量校验要前置到转换内,而非只靠下游 BI 发现。我们常用「校验」步骤判空、判范围、判枚举,非法行进错误表并让作业失败。质量左移,问题发现在源头最便宜。
对账是最后一道闸:源与目标关键指标(行数、合计、去重数)定期比对。我们日终作业末尾跑对账,差异超阈值即阻断下游报表。对账脚本本身也要随口径演进维护,不能写好就忘。
测试不是一次性的。我们给每个核心转换配冒烟,合并必跑;给季度大改配回归,重跑历史故障样本确认不再复现。测试资产和数据一起进版本库,才是可持续的质量。
下面这段 bash 给出了可直接落地的配置,输入来自上一步、输出写入目标端:
# CI 冒烟:用脱敏小样跑转换并断言 pan.sh /file:tests/smoke.ktr -param:p_day=TEST # 随后检查输出行数是否为预期(脚本比对) rows=$(mysql -e 'SELECT COUNT(*) FROM dwd_orders WHERE dt=TEST') [ "$rows" = "100" ] || exit 1
小样+断言是转换的单元测试。我们每个核心转换都配,CI 红则不准合并,质量门禁前置。
-- 转换内校验:金额非负、状态在枚举内 SELECT COUNT(*) FROM dwd_orders WHERE dt='${p_day}' AND (amount<0 OR status NOT IN ('A','B','C')); -- 结果非0则说明质量不符,作业应失败
质量左移的典型做法。我们把这类校验嵌进作业末尾,非法数据立刻现形而非流入报表。
一个核心转换要加字段,但没人敢改,因为没测试,怕改坏影响日终,于是长期绕路打补丁,债越积越深。
补一份脱敏小样+断言,作为该转换的冒烟,CI 合并必跑,之后放心重构。
pan.sh /file:order_sync.ktr -param:p_day=TEST [ $(rows) -eq 100 ] || exit 1 # 断言
有了安全网,团队大胆重构,转换从 18 步精简到 11 步,性能还提升,技术债开始偿还。
根因是缺测试带来的恐惧。测试不是额外负担,而是让变更「可放心发生」的前提,越早补越值。
进阶是把生产真实样本周期抽样做回归基线,变更后比对差异,抓隐性行为变化,比固定小样更灵敏。
误区:转换不用测。没测试没人敢改,技术债滚雪球。
误区:质量靠下游 BI 发现。左移到转换内校验,源头最便宜。
取舍:三层测试+对账闸;测试资产随数据进版本库。

回到工程现场,我们处理 9.4 测试策略与数据质量保证 时最忌讳只看单点性能而忽略端到端链路。9.4 测试策略与数据质量保证 的真实代价往往藏在步骤之间的缓冲与序列化里,而不是某一步骤本身。我们在多次压测中验证过这一点,并把对应的监控指标固化进自动化巡检脚本。当数据量翻倍时,瓶颈位置常会转移,因此不要把一次观测结论当成永久真理。
ETL 的 bug 会静默污染下游,所以测试比普通应用更该前置。我们分三层:单元测试针对单步骤(如值映射是否正确翻译),用「数据网格输入」步骤喂样例;集成测试跑端到端转换,断言输出行数、关键字段值;数据质量断言在作业收尾校验(空值率、主键唯一、行数波动阈值),不达标则失败告警。还要有回滚预案:测试环境与生产用相同结构,先在测试验证再上生产,避免拿生产当试验田。
-- 数据质量断言示例:校验当日结果的主键唯一与空值率(输入:dst_orders;输出:质量检查结果) SELECT 'dup_pk' AS chk, COUNT(*) AS bad FROM (SELECT id FROM dst_orders WHERE dt='${p_day}' GROUP BY id HAVING COUNT(*)>1) t UNION ALL SELECT 'null_amt', COUNT(*) FROM dst_orders WHERE dt='${p_day}' AND amount IS NULL; -- 若任一 bad>0,作业收尾步骤判失败并告警,阻断污染下游
| 层 | 测什么 | 手段 |
|---|---|---|
| 单元 | 单步骤逻辑 | 样例输入 |
| 集成 | 端到端 | 行数/值断言 |
| 质量 | 数据正确 | 约束校验 |
ETL 跑成功但数据错,比跑失败更危险。
收尾做主键唯一与空值率断言,不达标判失败。
SELECT 'dup_pk', COUNT(*) FROM ( SELECT id FROM dst_orders WHERE dt='${p_day}' GROUP BY id HAVING COUNT(*)>1) t UNION ALL SELECT 'null_amt', COUNT(*) FROM dst_orders WHERE dt='${p_day}' AND amount IS NULL; -- 任一 >0 则作业失败告警,阻断下游污染
脏数据在出口被拦,不再静默扩散。
ETL 失败常是静默的,断言专治此病。
测试覆盖脏数据,真实数据永远有意料外形状。
| 层 | 测什么 | 手段 |
|---|---|---|
| 单元 | 单步逻辑 | 样例 |
| 集成 | 端到端 | 断言 |
| 质量 | 数据正确 | 约束 |