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

Mar 16, 2025 - 15:44
 0
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 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!