Simplifying Test Data Generation with Drizzle ORM
Introduction At our company, we run tests using an actual database with Testcontainers instead of mocking the database during test execution. To conduct such tests, we need to prepare test data in advance. However, creating test data can become cumbersome, leading to reduced readability and increased maintenance efforts. To simplify test data generation, we developed the @praha/drizzle-factory package, which leverages Drizzle ORM. This article introduces the basic usage of @praha/drizzle-factory. If you find this article helpful, we would appreciate it if you could star our repository! https://github.com/praha-inc/drizzle-factory Difference from drizzle-seed drizzle-seed is an official Drizzle ORM tool for creating seed data for databases. It simplifies the data generation process by using a seedable pseudorandom number generator. On the other hand, @praha/drizzle-factory is designed to quickly build the necessary data when writing test cases. The key difference from drizzle-seed is that it focuses on explicitly generating data instead of relying on random values. In our team, we use it not to seed a complete dataset but to generate only the data required for each test case. How to Use @praha/drizzle-factory This section explains the basic usage of @praha/drizzle-factory, which is essentially the same as what is described in the README. Installation First, install the package. npm install -D @praha/drizzle-factory By adding the -D option, the library is added to devDependencies, meaning it will be used only in test and development environments rather than production. Although we do not recommend using it in production, if you need to, install it without the -D option: npm install @praha/drizzle-factory Defining a Factory To generate data, use the defineFactory function to define a factory. import { defineFactory } from '@praha/drizzle-factory'; import { pgTable, text, integer } from 'drizzle-orm/pg-core'; // We use PostgreSQL as an example, but other databases (MySQL, SQLite, etc.) are also supported. const schema = { users: pgTable('users', { id: integer().notNull(), name: text().notNull(), }), }; const usersFactory = defineFactory({ schema, table: 'users', // `sequence` is an incrementing value each time a new record is generated. resolver: ({ sequence }) => ({ id: sequence, name: `name-${sequence}`, }), }); Creating Data You can generate data using the defined factory. Creating a Single Record Calling create without arguments creates a single record. const user = await usersFactory(database).create(); console.log(user); /* { id: 1, name: 'name-1', } */ Creating Multiple Records Passing a number as an argument to create generates multiple records. const users = await usersFactory(database).create(3); console.log(users); /* [ { id: 1, name: 'name-1' }, { id: 2, name: 'name-2' }, { id: 3, name: 'name-3' }, ] */ Creating Records with Specific Values By passing an object or an array of objects to create, you can specify values for generated records. const user = await usersFactory(database).create({ name: 'John Doe' }); console.log(user); /* { id: 1, name: 'John Doe', } */ const users = await usersFactory(database).create([{ name: 'John Doe' }, { name: 'Jane Doe' }]); console.log(users); /* [ { id: 1, name: 'John Doe' }, { id: 2, name: 'Jane Doe' }, ] */ Generating Related Data You can also use other factories to automatically generate related records. const postsFactory = defineFactory({ schema, table: 'posts', resolver: ({ sequence, use }) => ({ id: sequence, // When using `use`, wrap it in a function to ensure it is only executed when needed. // This prevents unnecessary data creation when `userId` is explicitly specified. userId: () => use(usersFactory).create().then((user) => user.id), title: `title-${sequence}`, }), }); Executing create will automatically create records in the users table. const post = await postsFactory(database).create(); console.log(post); /* { id: 1, userId: 1, title: 'title-1', } */ Creating Variations with Traits Using traits, you can create data that matches specific conditions. const usersFactory = defineFactory({ schema, table: 'users', resolver: ({ sequence }) => ({ id: sequence, name: `name-${sequence}`, }), traits: { admin: ({ sequence }) => ({ id: sequence, name: `admin-${sequence}`, }), }, }); To generate data using a trait, call it from the traits property. const adminUser = await usersFactory(database).traits.admin.create(); console.log(adminUser); /* { id: 1, name: 'admin-1', } */ Composing Factories Instead of importing each factory individually, you can use composeFactory to combine multiple factories into one, making

Introduction
At our company, we run tests using an actual database with Testcontainers instead of mocking the database during test execution.
To conduct such tests, we need to prepare test data in advance.
However, creating test data can become cumbersome, leading to reduced readability and increased maintenance efforts.
To simplify test data generation, we developed the @praha/drizzle-factory package, which leverages Drizzle ORM.
This article introduces the basic usage of @praha/drizzle-factory
.
If you find this article helpful, we would appreciate it if you could star our repository!
https://github.com/praha-inc/drizzle-factory
Difference from drizzle-seed
drizzle-seed is an official Drizzle ORM tool for creating seed data for databases.
It simplifies the data generation process by using a seedable pseudorandom number generator.
On the other hand, @praha/drizzle-factory
is designed to quickly build the necessary data when writing test cases.
The key difference from drizzle-seed
is that it focuses on explicitly generating data instead of relying on random values.
In our team, we use it not to seed a complete dataset but to generate only the data required for each test case.
How to Use @praha/drizzle-factory
This section explains the basic usage of @praha/drizzle-factory
, which is essentially the same as what is described in the README.
Installation
First, install the package.
npm install -D @praha/drizzle-factory
By adding the -D option, the library is added to devDependencies
, meaning it will be used only in test and development environments rather than production.
Although we do not recommend using it in production, if you need to, install it without the -D option:
npm install @praha/drizzle-factory
Defining a Factory
To generate data, use the defineFactory
function to define a factory.
import { defineFactory } from '@praha/drizzle-factory';
import { pgTable, text, integer } from 'drizzle-orm/pg-core';
// We use PostgreSQL as an example, but other databases (MySQL, SQLite, etc.) are also supported.
const schema = {
users: pgTable('users', {
id: integer().notNull(),
name: text().notNull(),
}),
};
const usersFactory = defineFactory({
schema,
table: 'users',
// `sequence` is an incrementing value each time a new record is generated.
resolver: ({ sequence }) => ({
id: sequence,
name: `name-${sequence}`,
}),
});
Creating Data
You can generate data using the defined factory.
Creating a Single Record
Calling create
without arguments creates a single record.
const user = await usersFactory(database).create();
console.log(user);
/*
{
id: 1,
name: 'name-1',
}
*/
Creating Multiple Records
Passing a number as an argument to create
generates multiple records.
const users = await usersFactory(database).create(3);
console.log(users);
/*
[
{ id: 1, name: 'name-1' },
{ id: 2, name: 'name-2' },
{ id: 3, name: 'name-3' },
]
*/
Creating Records with Specific Values
By passing an object or an array of objects to create
, you can specify values for generated records.
const user = await usersFactory(database).create({ name: 'John Doe' });
console.log(user);
/*
{
id: 1,
name: 'John Doe',
}
*/
const users = await usersFactory(database).create([{ name: 'John Doe' }, { name: 'Jane Doe' }]);
console.log(users);
/*
[
{ id: 1, name: 'John Doe' },
{ id: 2, name: 'Jane Doe' },
]
*/
Generating Related Data
You can also use other factories to automatically generate related records.
const postsFactory = defineFactory({
schema,
table: 'posts',
resolver: ({ sequence, use }) => ({
id: sequence,
// When using `use`, wrap it in a function to ensure it is only executed when needed.
// This prevents unnecessary data creation when `userId` is explicitly specified.
userId: () => use(usersFactory).create().then((user) => user.id),
title: `title-${sequence}`,
}),
});
Executing create
will automatically create records in the users table.
const post = await postsFactory(database).create();
console.log(post);
/*
{
id: 1,
userId: 1,
title: 'title-1',
}
*/
Creating Variations with Traits
Using traits, you can create data that matches specific conditions.
const usersFactory = defineFactory({
schema,
table: 'users',
resolver: ({ sequence }) => ({
id: sequence,
name: `name-${sequence}`,
}),
traits: {
admin: ({ sequence }) => ({
id: sequence,
name: `admin-${sequence}`,
}),
},
});
To generate data using a trait, call it from the traits
property.
const adminUser = await usersFactory(database).traits.admin.create();
console.log(adminUser);
/*
{
id: 1,
name: 'admin-1',
}
*/
Composing Factories
Instead of importing each factory individually, you can use composeFactory
to combine multiple factories into one, making it easier to manage different tables.
import { composeFactory } from '@praha/drizzle-factory';
const factory = composeFactory({
users: usersFactory,
posts: postsFactory,
});
Using factory, you can manage data for different tables collectively.
const user = await factory(database).users.create();
console.log(user);
/*
{
id: 1,
name: 'name-1',
}
*/
const post = await factory(database).posts.create({ userId: user.id });
console.log(post);
/*
{
id: 1,
userId: 1,
title: 'title-1',
}
*/
Conclusion
Using @praha/drizzle-factory
, you can easily generate test data!
We hope this package helps improve test data management and readability in Drizzle ORM
projects. Give it a try!