Mock 数据是测试输入或替代依赖,并不会自动等于“安全的虚假用户数据”。随机姓名生成器可能产生看似合理的字符串,却违反数据库约束、向真实地址发邮件,或掩盖真正需要覆盖的边界。好的测试数据是有意设计的:它表达契约、失败模式或分布,并且可重新生成、审计和解释。
简明定义与术语边界见 Mock Data 术语页。需要为 UI 或 API 原型快速创建浏览器本地样本时,可使用随机数据生成器,再按自己的 Schema 和命名测试场景校验、调整输出。
核心要点
- 区分 fixture、stub、fake、模拟器、工厂和合成数据,它们解决不同测试问题。
- 假数据不等于生产数据匿名化。合成记录仍可能保留敏感分布、接近真实个人,或被发送到外部系统。
- 使用保留域名、文档 IP 段、支付服务商测试卡和不可路由端点;不要用通用 faker 为认证测试生成密钥或凭据。
- 保持外键、唯一性、时间关系、状态转换、地区设置和领域不变量。
- 需要快照和可重复性时,固定生成器、语言环境、时区、种子、Schema 和库版本。种子是复现元数据,不是安全秘密。
- 随机性本身覆盖能力有限。应组合代表性 fixture、边界案例、无效值、性质测试、契约校验和接近生产的负载分布。
测试替身与数据策略
| 策略 | 目的 | 常见控制 |
|---|---|---|
| Fixture | 稳定、经过审查的输入/输出 | 版本化文件 |
| Factory | 带覆盖参数地创建有效记录 | 默认值加场景参数 |
| Stub | 返回预设依赖结果 | 请求/参数匹配 |
| Fake | 轻量但可运行的实现 | 内存数据库或队列 |
| Simulator | 模拟时序、故障和外部行为 | 可控状态机 |
| 合成数据集 | 按分布生成大量记录 | 生成器、种子、来源和质量检查 |
| 匿名化数据 | 降低真实数据可链接性 | 威胁模型和再识别审查 |
不要把变换后的生产数据库导出称为 Mock 数据并认为隐私问题已经解决。匿名化和合成生成需要独立的威胁模型、访问控制、留存规则和删除流程。
从契约开始
生成记录前先写明:
- 必填/可选字段、类型、范围和格式;
- 唯一性、外键和跨记录关系;
- 状态转换和合法事件顺序;
- 时区、语言环境、货币、舍入和日历规则;
- 错误和授权场景;
- 绝不能输出、持久化或发送给第三方的字段。
使用系统边界相同的 JSON Schema、OpenAPI 契约、数据库约束或领域验证器校验生成数据。能生成合法 JSON 的生成器,仍可能创建不可能的业务状态。
安全值域
使用不会意外联系真实人员或系统的值:
| 字段 | 更安全的测试策略 |
|---|---|
| 邮箱 | [email protected] 或拦截邮件的 sink |
| 主机名/URL | https://api.example.test,并阻断外连 |
| IPv4/IPv6 | 192.0.2.0/24、198.51.100.0/24、2001:db8::/32 等文档地址 |
| 电话 | 服务商文档规定的测试号码,不使用随机真实号码 |
| 支付卡 | 支付服务商测试 PAN,只在 test mode 使用 |
| 密码/令牌 | 仅限测试作用域的专用 fixture 或生成秘密 |
| 姓名/地址 | 明确合成的值或审查过的本地 fixture |
| 图片 | 具备权利、尺寸确定的本地资源 |
不要生成看似真实的密码,再把它当 JWT 密钥、API key 或加密密钥。默认不要让测试 URL 发起网络请求,应使用阻断网络策略并断言外连已被拦截。
确定性与可复现性
可复现数据不仅需要数字种子,还要记录生成器与依赖版本、语言环境、时区、参考日期、Schema 修订、种子、生成选项和源代码提交:
import { faker } from "@faker-js/faker";
faker.seed(20260206);
faker.setDefaultRefDate("2026-02-06T00:00:00.000Z");
const user = {
id: "user-0001",
name: faker.person.fullName(),
email: "[email protected]",
createdAt: faker.date.past({ years: 2 }).toISOString(),
};
console.log(user);
库版本变化可能改变精确 API 和输出。应固定版本;如果生成数据有意演进,也不要把快照当作唯一断言。
种子不是秘密。它适合复现测试,不得用于安全令牌、密码材料、会话 ID、加密密钥或密码学熵源。
工厂与不变量
工厂应让有效默认值容易生成,让无效场景显式表达:
type User = {
id: string;
email: string;
status: "active" | "suspended";
createdAt: string;
};
let sequence = 0;
export function buildUser(
overrides: Partial<User> = {},
): User {
sequence += 1;
return {
id: `user-${sequence.toString().padStart(4, "0")}`,
email: `user-${sequence}@example.test`,
status: "active",
createdAt: "2026-02-06T00:00:00.000Z",
...overrides,
};
}
const suspended = buildUser({ status: "suspended" });
关系型数据应先创建父记录再创建子记录,保留外键引用,并在测试间重置状态。时间相关测试应注入时钟,而不是在工厂里读取墙上时钟。并发测试不要共享全局可变计数器,或应隔离每个测试的生成器状态。
边界与性质测试
普通平均记录远远不够,应有意覆盖:
- 空、最小、最大和超限字符串;
- Unicode 组合字符、RTL 文本、emoji 和混合文字;
- 零、负数、大数、小数,以及相关场景对
NaN/无穷的拒绝; - 缺失、
null、重复、未知和乱序字段; - 闰日、夏令时切换、时区偏移、过期和未来时间戳;
- 重复 ID、孤立引用、冲突状态、重试和幂等场景;
- 未授权租户、畸形令牌、超时、部分失败和限流。
性质测试生成器可以探索组合,但每个失败种子都应保存为回归 fixture。随机探索应补充而不是替代能解释业务规则的命名示例。
API 与数据库测试
API 测试应将响应 fixture 与请求工厂分开,断言状态码、响应头、Schema、授权、错误结构和副作用。HTTP 成功状态不证明响应或数据库状态正确。
数据库测试应:
- 通过领域约束生成记录,或插入前验证;
- 使用隔离数据库或事务;
- 为性能测试使用接近真实的索引和基数;
- 不用很小的随机数据集宣称生产查询表现;
- 按留存策略清理或销毁测试数据。
性能数据集应记录行数、分布、倾斜、热点键、并发、查询组合、硬件、缓存状态和测量日期。“生成一百万条随机记录”不是负载模型。
地区、文本与 Lorem Ipsum
带语言环境的生成器有助于 UI 和国际化测试,但库的 locale 不保证姓名、地址、电话号码或法律数据在文化上有效。应测试长译文、缺字形、复数规则、日期/数字格式、RTL 布局和文字脚本变化。
Lorem Ipsum 只近似拉丁文字密度,不代表真实语言行为。它不能测试翻译长度、屏幕阅读器语义、搜索、复制粘贴、内容审核或 RTL 布局。相关需求应使用经过审查的本地化字符串和明确长度分布;装饰性占位文本应标记,避免被读成有意义内容。
带校验意识的 Faker 示例
Faker 等库是便利生成器,不是 Schema 验证器:
from dataclasses import dataclass
from datetime import datetime, timezone
@dataclass(frozen=True)
class User:
user_id: str
email: str
created_at: datetime
def build_user(index: int) -> User:
if index < 1:
raise ValueError("index must be positive")
return User(
user_id=f"user-{index:04d}",
email=f"user-{index:04d}@example.test",
created_at=datetime(2026, 2, 6, tzinfo=timezone.utc),
)
增加独立的 Schema/领域校验步骤,并为无效覆盖值编写测试。不要认为库生成的“看似有效”电话、卡号、URL 或地址可以安全发送或具有法律意义。
Mock 服务与故障模拟
Mock 服务应模拟 API 契约和受控故障,而不是只返回随机 JSON。应为以下场景定义响应 fixture:
- 成功、空结果、部分结果和分页;
- Schema 无效和未知字段响应;
- 认证失败、授权拒绝、限流、超时、重试和取消;
- 重复投递、事件乱序和幂等冲突。
单元测试中的网络调用应确定性地拦截。真实协议行为放到集成或预发布环境测试,并使用隔离凭据和明确数据删除流程。
隐私与治理
如果合成数据来自生产分布、包含复制值,或被发送给第三方生成器,它仍可能敏感。应维护数据集与产物清单,限制访问,按需要加密,扫描日志和快照,并记录留存与删除。
不要把真实凭据、访问令牌、私钥、个人标识符或生产数据库导出放进 fixture。测试仓库同样是数据边界。
常见问题
Mock 数据总是隐私安全吗?
不是。纯合成值可以减少暴露,但生成器可能产生真实联系信息、复制模板或敏感分布。应使用保留域名和测试值,阻断网络投递,并审查来源。
种子需要保密吗?
不需要。种子是复现元数据,绝不能用于密码、令牌、密钥或安全原语的熵。
随机 Mock 数据能替代边界测试吗?
不能。随机数据可能错过罕见组合,也不会记录预期不变量。应把命名边界 fixture 与性质测试结合。
Mock 数据可以用于生产吗?
只有在它是明确标注的产品行为时才可以,例如空状态演示。它不能静默替代真实业务数据、授权决策、计费记录或审计证据。
如何安全测试支付字段?
使用支付服务商文档规定的测试模式和测试卡号,隔离凭据,并断言应用不会把测试数据发送到生产端点。不要自行编造号码并称为有效支付工具。
Lorem Ipsum 适合 UI 测试吗?
它适合拉丁文字布局的粗略密度测试,但不能测试本地化、语义、无障碍、搜索、审核或 RTL 行为。相关需求应使用代表性的本地化 fixture。
一手来源
- RFC 2606:保留顶级 DNS 名称
- RFC 5737:IPv4 文档地址段
- RFC 3849:IPv6 文档地址前缀
- OWASP:Top 10
- W3C Web Content Accessibility Guidelines (WCAG) 2.2
- Faker.js 文档
总结
高质量 Mock 数据是受控的测试工具,而不是一堆看似真实的随机记录。应先定义契约,保持关系和不变量,使用保留值域,固定复现元数据,生成命名失败场景,独立校验,并治理每个数据集和产物。这样可以提高测试信号,同时避免隐私、投递和安全风险。