Python 测试数据与真实数据的差距问题

2次阅读

真实数据常因字段缺失、接口变更、浮点精度、时区不一致导致测试通过但线上出错;应显式校验字段存在性、用真实响应做mock、math.isclose比较浮点数、统一utc时区构造时间。

Python 测试数据与真实数据的差距问题

测试数据太“干净”,真实数据一跑就报 KeyError

测试时用的是手写的字典或 json 片段,字段全、类型稳;线上一读 CSV 或 API 返回,data['user_id'] 直接炸——因为有些记录压根没这个 key,或者值是 None

根本原因不是数据“脏”,而是测试没覆盖「字段缺失」这个最常见现实场景。

  • 写断言前先用 assert 'user_id' in datadata.get('user_id') is not None 显式检查,别依赖 data['user_id']
  • 生成测试数据时,用 random.choice([True, False]) 控制 20%~30% 的样本故意缺关键字段
  • 如果用 pandas,注意 df['user_id'].values 在列不存在时抛 KeyError,而 df.get('user_id') 返回 None,更贴近真实容错逻辑

pytest 里 mock 的返回值和真实 API 响应结构不一致

mock 一个 requests.get,返回 {'result': [...], 'code': 0};但真实接口某天加了 'meta' 字段,或把 'result' 改成 'items',测试照过,代码上线就挂。

这不是 mock 写得不好,是 mock 没跟真实响应做双向对齐。

立即学习Python免费学习笔记(深入)”;

  • 上线前抓一次真实响应存为 tests/fixtures/api_v2_user.json,测试时用 json.load() 读它来构造 mock 返回值
  • 在 CI 中加一步:用 jsonschema 验证 mock 数据是否符合当前接口的 OpenAPI schema(哪怕只是简单校验字段名)
  • 避免在 test 文件里硬编码结构,比如不要写 mock_resp.json.return_value = {'data': {...}},改用 load_json_fixture('user_list_response.json')

浮点数精度导致测试通过、生产计算结果偏差

测试用 0.1 + 0.2 == 0.3 断言,本地过;但真实数据来自数据库 Float 列或 C++ 服务返回的二进制 float,实际值是 0.30000000000000004,断言失败,或后续聚合出错。

pythonfloat 和数据库/其他语言的 float 表示方式一致,但输入源不同,舍入路径就不同。

  • 测试中所有浮点比较改用 math.isclose(a, b, abs_tol=1e-9),别用 ==
  • 从数据库读数值时,优先用 Decimal(如 cursor.execute("select CAST(price AS DECIMAL) FROM ...")),避免 float 中间态
  • 如果必须用 float,确保测试数据也走同一套解析逻辑——比如别手工写 0.1,而是从同一条 sql 或同一个 CSV 解析器加载

时间字段在测试和生产环境时区行为不一致

本地测试用 datetime.now(),UTC 时间戳硬编码进 fixture;生产环境服务器在东八区,datetime.now() 返回带 +08:00 的 datetime,一比对就错,尤其涉及 timedelta 计算或数据库 timestamp WITH TIME ZONE

问题不在“用不用 timezone”,而在「测试数据的时间语义」和「生产时间上下文」没对齐。

  • 所有测试中的时间构造统一用 datetime(2024, 5, 1, 12, 0, 0, tzinfo=timezone.utc),显式带 tzinfo,不依赖系统时区
  • 避免用 time.time()datetime.utcnow()(后者已弃用),改用 datetime.now(timezone.utc)
  • 如果业务逻辑本身要处理本地时间(如“今天 0 点”),测试时明确传入 timezone(timedelta(hours=8)),而不是靠环境变量或系统设置隐式生效

真实数据从来不会配合你的测试假设出现。最危险的不是报错,是静默偏差——比如金额少算 0.0001 元、时间窗口漏掉 1 秒、字段缺失被默认值掩盖。盯住数据源头的表示形式,比盯住代码逻辑更管用。

text=ZqhQzanResources