功能说明
该示例实现一个链式测试数据构造器。它先接收一组默认字段,之后可以多次 with 叠加覆盖,最后 build 出完整对象。buildList 能按数量生成一组数据,并允许根据下标为每条记录注入不同字段,适合构造用户、订单、文章等测试夹具,避免在每个用例里复制大段对象字面量。
关键代码
createBuilder 保存 defaults 与 layers 数组。build 使用 Object.assign 按默认值、各层覆盖、最后一次覆盖的顺序合并,后写入者优先。with 校验参数必须是普通对象后入栈并返回自身,从而支持链式调用。reset 清空覆盖层,便于不同测试之间复用同一个构造器。buildList 校验数量为非负整数,并把下标传给回调生成差异字段。
使用注意
合并是浅合并,嵌套对象会被整体替换而不是递归合并,需要深层差异时应使用深合并工具。layers 会持续累积,跨用例复用前应调用 reset。默认值中的数组或对象会被多个结果共享引用,测试中修改嵌套结构可能互相污染。构造器不会自动生成唯一 ID,需要唯一值时应在回调中显式赋值。
验证方式
断言 with 覆盖 role 后 build 得到 admin,同时保留默认 active。调用 reset 后再次 build 断言 role 回到 member。用 buildList 生成两条记录,断言 id 分别为 1 和 2 且互不共享顶层对象。测试负数数量、非函数回调与非对象覆盖分别抛错。
代码示例
export function createBuilder(defaults) {
if (defaults === null || typeof defaults !== "object" || Array.isArray(defaults)) {
throw new TypeError("defaults must be a plain object");
}
const layers = [];
const build = (overrides = {}) => Object.assign({}, defaults, ...layers, overrides);
const assertOverrides = (overrides) => {
if (overrides === null || typeof overrides !== "object" || Array.isArray(overrides)) {
throw new TypeError("overrides must be a plain object");
}
};
const api = {
with(overrides) {
assertOverrides(overrides);
layers.push(overrides);
return api;
},
reset() {
layers.length = 0;
return api;
},
build,
buildList(count, overrides = () => ({})) {
if (!Number.isInteger(count) || count < 0) {
throw new RangeError("count must be a non-negative integer");
}
if (typeof overrides !== "function") throw new TypeError("overrides must be a function");
return Array.from({ length: count }, (_, index) => build(overrides(index)));
},
};
return api;
}
const user = createBuilder({ role: "member", active: true });
console.log(user.with({ role: "admin" }).build({ name: "Ada" }));
console.log(user.reset().buildList(2, (index) => ({ id: index + 1 })));