测试数据管道:验证内容与时机
Source: Dev.to

如果你问一个应用开发者他们如何测试代码,他们会描述单元测试、集成测试、CI/CD 流水线和覆盖率指标。若你向数据工程师提出同样的问题,最常见的回答是:“我们查看仪表盘。”
数据管道也是软件。它们有输入、逻辑和输出。它们可能存在缺陷,可能会悄然失效。而且不同于会触发错误页面的应用程序错误,数据错误会产生看似合理的数字——直到有人基于这些数字做出业务决策。
管道是软件——它们需要测试
数据管道的测试标准不应低于应用代码的标准,甚至应该更高。应用程序的错误通常是可见的(界面崩溃、请求失败),而数据错误往往是隐形的(聚合错误、缺少行、值过期),且其影响会随时间累积。
然而,大多数数据团队并没有自动化测试。他们依赖手动抽查、分析师的投诉以及运气。对管道进行测试意味着要在问题到达消费者之前 捕获 它们,而不是事后处理。
数据测试金字塔
借鉴软件工程中的测试金字塔,并将其应用于数据:
| 层级 | 关注点 | 特征 |
|---|---|---|
| 底层 | 模式和契约测试 | 快速、低成本,在每次管道执行时运行。验证输出模式是否符合消费者的期望(列、数据类型、约束)。 |
| 中层 | 数据验证测试 | 检查输出中的数值(唯一性、非空、范围、引用完整性)。 |
| 顶层 | 回归和集成测试 | 将今天的输出与历史模式进行比较(行数、总计、分布)。 |
在底层运行更多测试(它们便宜且快速),在顶层运行较少测试(它们昂贵但全面)。
架构和契约测试
架构测试是最简单且最具影响力的起点。每次管道运行后,验证:
- 列存在性 – 每个预期的列都存在。
- 数据类型 – 列具有预期的数据类型。
- 非空约束 – 必填列不包含空值。
- 唯一性 – 主键列没有重复值。
-- Example schema and contract tests
-- Check for unexpected nulls
SELECT COUNT(*) AS null_count
FROM orders
WHERE order_id IS NULL OR customer_id IS NULL;
-- Check for duplicates
SELECT order_id, COUNT(*) AS cnt
FROM orders
GROUP BY order_id
HAVING COUNT(*) > 1;

运行时数据验证
- 范围检查 – 数值应落在预期范围内(例如,订单总额不应为负数)。
- 参照完整性 – 外键应引用已存在的记录。
- 新鲜度检查 – 最近的事件时间戳应在预期窗口内。
- 量级检查 – 行数应保持在历史常规范围内(例如,最近 7 天平均值的 ±20 %)。
- 自定义业务规则 – 领域特定的断言,例如 “每张发票必须至少有一项明细” 或 “任何员工的入职日期都不应在未来”。
回归与异常检测
回归测试将今天的输出与历史基准进行比较:
- 聚合比较 – 将关键指标(总收入、行数、唯一客户计数)与上一次运行进行比较。标记超出阈值的偏差(例如,±15 %)。
- 分布检查 – 将分类列的分布(状态值、国家代码)与历史常规进行比较。“unknown”状态的突增可能表明源模式发生了变化。
- 趋势分析 – 随时间监控指标,以检测可能表明上游数据质量问题的逐渐漂移。
通过将快速模式检查与全面回归检查分层进行,数据团队可以及早捕获错误,保持对管道的信心,并避免因错误数据导致的高成本下游决策。
随时间跟踪指标
随着周数的推移,行数逐渐下降可能表明存在每日检查未能发现的泄漏。
回归测试的维护成本更高,因为它们需要历史基线和阈值调优。
从简单做起(行数 ± 20 %),并在了解“正常”状态后逐步细化。
接下来该做什么
今天为您最关键的流水线添加三个测试:
- 对主键进行 唯一性检查。
- 对必填列进行 空值检查。
- 将行数与昨天的输出进行 行数比较。
在每次流水线执行后运行它们。这三个测试即可捕获大多数数据问题,防止其传递给消费者。
