Jest + Prisma + PostgreSQL でテストごとにデータベースをリセットしながらユニットテストする
Jest + Prisma + PostgreSQL でテストごとにデータベースをリセットしながらユニットテストする。
モックしてDBと切り離してテストしても良いが、折角開発環境にDBもあることなので、本番さながらに動かしてみてテストしたい。
まずはデータベースをリセットするヘルパーを書いていく。
import prisma from '../lib/prisma' // new PrismaClient() したやつ
export const resetDatabase = async (): Promise<void> => {
const tableNames = (
await prisma.$queryRawUnsafe(
`SELECT tablename FROM pg_catalog.pg_tables WHERE hastriggers = true;`
) as { tablename: string }[]
).map(({ tablename }) => tablename)
await prisma.$transaction(tableNames.map((tableName) => (
prisma.$queryRawUnsafe(`TRUNCATE TABLE "${tableName}" RESTART IDENTITY CASCADE;`)
)))
}
prisma migrate reset
で丸ごとリセットする方法もあるようだが、それだとコネクションが切れてうまく繋ぎ直せない時があり不安定だった。
テーブルの一覧を取得して、一つずつ TRUNCATE TABLE "${tableName}" RESTART IDENTITY CASCADE;
していく方法が安定して動いた。
あと本当は Unsafe じゃない $queryRaw
を使った方が良い。(テストの時しか使わないし一旦これで)
package.json の scripts にこんなの入れてみた。
{
"scripts": {
"test": "DATABASE_URL='postgresql://postgres:postgres@localhost:5432/app?schema=test' npm run test:exec",
"test:exec": "prisma migrate dev && jest --runInBand",
}
}
環境変数で設定されているデータベースのURLを書き換えている。スキーマを test
として、動作確認などで使う DB と分けた。
test
と test:exec
があるのは、環境変数の設定を二度書くのが面倒だったため。(なんかいいやり方あるのかな)
それと大切なのが、jestコマンド実行時に必ず --runInBand
オプションを入れること。
これを入れないとデフォルトでテストが並列で実行されてしまい、どえらいことになる。
このせいで無限に時間溶かした。
僕を救ってくれたありがたい記事を紹介しておきます🙏
Jestテストの並行実行と逐次実行をちゃんと理解する
テストコードで先ほどのヘルパーをインポートして、テストごとに resetDatabase()
を実行させる。
beforeEach(async() => {
await resetDatabase()
})
npm run test
でたぶんうごく