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/24198.51.100.0/242001:db8::/32 等文档地址
电话 服务商文档规定的测试号码,不使用随机真实号码
支付卡 支付服务商测试 PAN,只在 test mode 使用
密码/令牌 仅限测试作用域的专用 fixture 或生成秘密
姓名/地址 明确合成的值或审查过的本地 fixture
图片 具备权利、尺寸确定的本地资源

不要生成看似真实的密码,再把它当 JWT 密钥、API key 或加密密钥。默认不要让测试 URL 发起网络请求,应使用阻断网络策略并断言外连已被拦截。

确定性与可复现性

可复现数据不仅需要数字种子,还要记录生成器与依赖版本、语言环境、时区、参考日期、Schema 修订、种子、生成选项和源代码提交:

javascript
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、加密密钥或密码学熵源。

工厂与不变量

工厂应让有效默认值容易生成,让无效场景显式表达:

typescript
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 成功状态不证明响应或数据库状态正确。

数据库测试应:

  1. 通过领域约束生成记录,或插入前验证;
  2. 使用隔离数据库或事务;
  3. 为性能测试使用接近真实的索引和基数;
  4. 不用很小的随机数据集宣称生产查询表现;
  5. 按留存策略清理或销毁测试数据。

性能数据集应记录行数、分布、倾斜、热点键、并发、查询组合、硬件、缓存状态和测量日期。“生成一百万条随机记录”不是负载模型。

地区、文本与 Lorem Ipsum

带语言环境的生成器有助于 UI 和国际化测试,但库的 locale 不保证姓名、地址、电话号码或法律数据在文化上有效。应测试长译文、缺字形、复数规则、日期/数字格式、RTL 布局和文字脚本变化。

Lorem Ipsum 只近似拉丁文字密度,不代表真实语言行为。它不能测试翻译长度、屏幕阅读器语义、搜索、复制粘贴、内容审核或 RTL 布局。相关需求应使用经过审查的本地化字符串和明确长度分布;装饰性占位文本应标记,避免被读成有意义内容。

带校验意识的 Faker 示例

Faker 等库是便利生成器,不是 Schema 验证器:

python
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。

一手来源

总结

高质量 Mock 数据是受控的测试工具,而不是一堆看似真实的随机记录。应先定义契约,保持关系和不变量,使用保留值域,固定复现元数据,生成命名失败场景,独立校验,并治理每个数据集和产物。这样可以提高测试信号,同时避免隐私、投递和安全风险。