Closed3

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 と分けた。
testtest:exec があるのは、環境変数の設定を二度書くのが面倒だったため。(なんかいいやり方あるのかな)

それと大切なのが、jestコマンド実行時に必ず --runInBand オプションを入れること。
これを入れないとデフォルトでテストが並列で実行されてしまい、どえらいことになる。
このせいで無限に時間溶かした。

僕を救ってくれたありがたい記事を紹介しておきます🙏
Jestテストの並行実行と逐次実行をちゃんと理解する

みのじろーみのじろー

テストコードで先ほどのヘルパーをインポートして、テストごとに resetDatabase() を実行させる。

beforeEach(async() => {
  await resetDatabase()
})

npm run test でたぶんうごく

このスクラップは2021/11/30にクローズされました