[node 库推荐] rosie 测试用生成数据
最近发现一个用来生成 dummy data 非常好用的库,做测试或者 storybook 都挺合适的,npm 官方地址在 rosie,同时有 TS 支持
rosie 用的是 factory pattern,使用真的还蛮简单的,官方文档也比较直接,这里走一下流程,简单的过一下怎么用这个 package
定义和创建对象
这里用一个比较简单的 User
作为案例好了,比如说 User
的类型为:
type IUser = {
id: number;
firstName: string;
lastName: string;
};
实现方式如下:
import { Factory } from "rosie";
Factory.define("user")
.sequence("id")
.attr("firstName", "First Name")
.attr("lastName", "Last Name");
console.log(Factory.build("user"));
其中 sequence
类似于 id 生成
定义和创建多个对象
如果只需要创建一个对象,那么其实手动 type 会更方便一些,不过总会遇到需要生成一组数据,这个时候就能体现 rosie 的优势:
import { Factory } from "rosie";
Factory.define("user")
.sequence("id")
.attr("firstName", "First Name")
.attr("lastName", "Last Name");
const users = Factory.buildList("user", 10);
users;
如果再搭配 faker 进行使用:
import { Factory } from "rosie";
import { faker } from "@faker-js/faker";
Factory.define("user")
.sequence("id")
.attr("firstName", () => faker.person.firstName())
.attr("lastName", () => faker.person.lastName());
const users = Factory.buildList("user", 10);
users;
那么就能够生成 10 个随机的用户信息
嵌套对象
这里的补全一下用户的定义,使其结构大致如下:
type IAddress = {
addr1: string;
addr2?: string;
zipcode: string;
city: string;
state: string;
};
type IUser = {
id: number;
firstName: string;
lastName: string;
address: IAddress;
};
用 rosie 也能够简单的达成目的:
import { Factory } from "rosie";
import { faker } from "@faker-js/faker";
// define address object
Factory.define("address")
.attr("addr1", () => faker.location.streetAddress())
.attr("addr2", () => {
if (Math.random() < 0.5) {
return undefined;
}
return faker.location.secondaryAddress();
})
.attr("zipcode", () => faker.location.zipCode())
.attr("city", () => faker.location.city())
.attr("state", () => faker.location.state());
// define user object
Factory.define("user")
.sequence("id")
.attr("firstName", () => faker.person.firstName())
.attr("lastName", () => faker.person.lastName())
.attr("address", () => Factory.build("address"));
// create list
const users = Factory.buildList("user", 10);
users;
其他
其实大多数功能这几个函数就能实现了,接下来列举一下可能会碰到的一些其他方法
reset
reset 和 resetAll 是用来重设 Factory 的方法,这个比较多的可以搭配在 beforeEach
或是一些其他的条件去进行,同样也是方便测试
new
这里是 new 一个 factory,主要创建一个新的未注册工厂,这个主要适配 node 的模块化设计模式:
import { Factory } from "rosie";
import { faker } from "@faker-js/faker";
const AddressFactory = new Factory()
.attr("addr1", () => faker.location.streetAddress())
.attr("addr2", () => {
if (Math.random() < 0.5) {
return undefined;
}
return faker.location.secondaryAddress();
})
.attr("zipcode", () => faker.location.zipCode())
.attr("city", () => faker.location.city())
.attr("state", () => faker.location.state());
Factory.define("player")
.sequence("id")
.attr("firstName", () => faker.person.firstName())
.attr("lastName", () => faker.person.lastName())
.attr("address", () => AddressFactory.build());
const users = Factory.buildList("player", 10);
users;
这种实现下,AddressFactory
也可以被 export 到其他的地方反复使用,而不需要使用 Factory singleton
options
前面是否生成第二个地址采取的使用一个伪随机的方式去生成的,不过 rosie 也支持通过参数的方法实现,如:
const AddressFactory = new Factory()
.option("withAddr2", true)
.attr("addr1", () => faker.location.streetAddress())
.attr("addr2", ["withAddr2"], (withAddr2) => {
console.log(withAddr2);
return withAddr2 ? faker.location.secondaryAddress() : undefined;
})
.attr("zipcode", () => faker.location.zipCode())
.attr("city", () => faker.location.city())
.attr("state", () => faker.location.state());
Factory.define("player")
.sequence("id")
.attr("firstName", () => faker.person.firstName())
.attr("lastName", () => faker.person.lastName())
.attr("address", () => AddressFactory.build({}, { withAddr2: false }));
const users = Factory.buildList("player", 1);
users;
效果如下:
这样可以根据一些条件去生成对应的属性,以便于更加灵活可控的进行测试