Hono + Prisma + PrismockでDBなしでテストを実行する
皆さんPrisma使ってますか!
この記事ではHono + Prismaの構成にPrismockとprisma-fabbricaいうライブラリを使ったテストの例を紹介します
PrismockはPrismaをインメモリ上のDBでエミュレートするもので、prisma-fabbricaはPrismaでmodelのFactoryを自動生成するものです
説明するよりコードを見たほうが早いと思うため、コードを先に載せます
実践
下記のHandlerのテストコードを書きます
export const taskCreateHandler: AppRouteHandler<CreateRoute> = async (c) => {
const prisma = c.get('prisma');
const data = c.req.valid('json');
const count = await prisma.task.count();
if (count >= 10) {
return c.json({ message: 'Maximum number of tasks (10) reached' }, 400);
}
const task = await prisma.task.create({
data: {
title: data.title,
completed: false,
},
});
return c.json(task, 201);
};
準備としてテスト用のutlilを作成
test-utils.ts
// ...省略
export const setupTestApp = <R extends AppOpenAPI>(routes: R, options: TestSetupOptions = {}) => {
const prisma = createPrismaMockClient();
const env = { ...defaultTestEnv, ...options.env };
const app = createTestApp(routes, prisma, env);
// Honoのテストクライアントを生成
const client = testClient(app);
// prisma-fabbricaにPrismockのクライアントを渡す
initialize({ prisma });
// Prismockにて追加されたreset() テストケース毎にインメモリ上のDBをリセットしている
beforeEach(() => prisma.reset());
return {
prisma,
app,
client,
};
テスト作成
task.create.test.ts
import { defineTaskFactory } from '@/../prisma/src/__generated__/fabbrica';
import tasks from '@/app/task/routes/task.index';
import { setupTestApp } from '@/lib/test-utils';
import { describe, expect, it } from 'vitest';
describe('TaskCreateHandler', () => {
// この中でPrismockを注入している
const { client } = setupTestApp(tasks);
// prisma-fabbricaによるFactory自動生成
const TaskFactory = defineTaskFactory();
// ...省略
describe('上限チェック', () => {
it('Task数が上限に達している場合はエラー', async () => {
// Prismockとprisma-fabbricaの合わせ技でインメモリ上にデータ10件生成
await TaskFactory.createList(10);
// hono/testingのtestClientでリクエスト
// Handler内では上記でPrismaのMockを注入しているため、コードそのままでインメモリ上で動く
const res = await client.tasks.$post({
json: { title: 'テストTask' },
});
expect(res.status).toBe(400);
// DB立ち上げずにエディタ上でVitestぽちでちゃんと上限10件のテストが動く
expect(await res.json()).toEqual({
message: 'Maximum number of tasks (10) reached',
});
});
// beforeEach(() => prisma.reset()); がutilに書いてあるのでこのテストケースではインメモリのDBがリセットされている
it('Task数が上限未満の場合は作成できる', async () => {
await TaskFactory.createList(9);
const res = await client.tasks.$post({
json: { title: 'テストTask' },
});
expect(res.status).toBe(201);
});
});
});
コード全体を見たい方は下記のリポジトリを参照してください
(色々コード雑なのは許して、、)
結論
これのなにがいいかって超高速でテストが実行できることと、DBを用意する必要なくテストが実行できることです
テストコード内でPrismaのコードを書く場合は
const { client, prisma } = setupTestApp(tasks);
const test = await prisma.task.findMany();
console.table(test);
みたいに書くとデータが生成されているのが確認できます
こんな感じ
Prismaをモックする方法は公式にもあるのですが、公式ドキュメントの方法でモックしようとしたらかなり煩わしいし、かといってRepository作るほどのものを開発していない場合も多いと思います
Prismockを使えば効率良くテストコードの記述が可能です!
ある程度のものはモックしてくれますが、いくつかモックできないパターンもあるようなので、利用する際は下記を見ると良いと思います
morintd/prismock: A mock for PrismaClient, dedicated to unit testing.
基本的なものは対応しているのですが、raw系とかTypedSQLは無理そう(空が返ってるぽい)
無理なやつはPrisma公式の方法で諦めてモック頑張って書きましょう、、
HonoはDrizzleとセットで使われることが多いですが(PrismaはCloudflare Workers環境でセットアップがややこしい)Prismaで効率的に開発するのも良いかなと思います!
※現状Prisma6.2.1ではMiniflare環境で起動時にエラー吐くので下記のshでモンキーパッチあててます
短いですがPrismockの紹介でした!
Discussion