【Prismaとテストシリーズ】テスト実行用のDBとローカル環境開発用のDBを使い分けてみた

「ローカル開発環境で作業している時に余計なレコードを生成してたからPrismaを使ったテストでユニーク制約に引っかかってテスト失敗した」、「ローカルの開発環境とテストの世界を切り離したい」そんなモチベーションでやり方を調べてみました。RailsやLaravelでもテスト用のDB設定ができるので、それをイメージしました。
2023.10.01

こんにちは。AWS事業本部モダンアプリケーションコンサルティング部に所属している今泉(@bun76235104)です。

PrismaはTypeScriptでも利用できるORMの一つです。

前回、以下の記事では「テストケースごとに隔離されたトランザクションで、安全にテストしたいなー」というモチベーションでjest-prismaというライブラリを試してみました。

今回はこれに加えて「ローカル開発で利用するDB」と「テスト実行時に利用するDB」を分けてみました。

状況 接続するDB
ローカル環境での開発時 sample
テスト時 sample_test

さっそくまとめ

  • Prisma公式ドキュメントに記載されている「複数の.envファイルを利用する方法」によりあっさり解決できました
  • 嬉しいポイント
    • ローカルでデータを生成していても、その結果がテストに影響しない
    • テスト用のDBが不整合な状態になっても、何の躊躇いもなくレコードを消すなどの運用ができる
    • 要するに、「テストを実行する際の環境」と「普段ローカルで開発しながらシステムを動かす際の環境」が互いに影響を与える可能性を低くする

作業の流れ

事前準備

通常Prismajestなどの設定が必要となりますが、今回その準備の工程は省かせていただきます。

利用しているソースコードなどは以下のリポジトリに配置しているため、興味がある方はご確認ください。

dotenvの準備

先ほども言及したUsing multiple .env files. | Prisma Docsの手順に従って作業をしました。

まずは、.env.testというファイルを.envと同様にプロジェクトルートに作成します。

.env.test

DATABASE_URL="mysql://ユーザー名:パスワード@localhost:3306/sample_test"

ちなみに.envは以下のように記述しており、利用するDBが異なるだけです。

.env

DATABASE_URL="mysql://ユーザー名:パスワード@localhost:3306/sample"

次にdotenv-cliをインストールします。今回はグローバルインストールではなく、devDependenciesにインストールしました。

npm i -D dotenv-cli

package.jsonのscriptsを修正

テスト実行時に.env.testを読み取ってくれるように以下のようにpackage.jsonのscriptsを修正します。

{
  "scripts": {
    "test": "dotenv -e .env.test -- jest",
    "migrate:test": "dotenv -e .env.test -- prisma migrate reset -f"
  }
}

npmを利用する際は npm run testを実行するだけで、テスト用のDBを参照してくれてとても良いです。

またテスト用のDBにマイグレーションを適用、ゴミデータの削除などを行うためにnpm run migrate:testというコマンドも準備しています。

その他、テスト用DBにseedコマンドを適用したい場合なども、同様のやり方でscriptsを組めると思います。

なお、プロジェクトで利用する環境変数がDATABASE_URLだけである場合は、以下のようにscriptsを組むだけでも良いと思います。

{
  "scripts": {
    "test": "DATABASE_URL=任意の値 jest",
  }
}

しかし、実際のプロジェクトの場合他にも「外部のシステム接続用の情報」などを管理することもあると思いますので、doenvを利用する方法の方が管理がしやすいかもしれません

実際にやってみる

ここまでの設定によりコマンドを実行すると、以下のように.env.testの情報を読み取って意図したとおりにsample_testというテスト用のDBに接続してくれました。

> prisma_test@1.0.0 test
> dotenv -e .env.test -- jest

 PASS  src/users/users.repository.spec.ts
  UsersRepository
    createUser
      ✓ should return a user (22 ms)
      ✓ should return a user2 (25 ms)
    updateUser
      ✓ updates user name (17 ms)
      ✓ updates user name (15 ms)

Test Suites: 1 passed, 1 total
Tests:       4 passed, 4 total
Snapshots:   0 total
Time:        1.247 s
Ran all test suites.

試しに開発用DBにテストの成功を阻害するようなデータを投入しておきましたが、当然問題なく動作しました。

さいごに

今回と前回はとにかく「テストと開発環境の世界を切り分けたい」というモチベーションで試してみました。

結果として良さげな環境を再現できたので、本格的なプロジェクトでも試していきたいと思います。

以上、最後までご覧いただきありがとうございました。

今泉でした。