2023年3月24日

Prisma を使ったテストの究極ガイド: CI パイプライン

継続的インテグレーション (CI) とは、複数の開発者によるコード変更を安全に中央リポジトリに統合するプロセスを指します。この記事では、CI パイプラインとは何か、CI パイプラインを構成する方法、およびそのパイプラインを使用してテストを自動化する方法について詳しく学びます。

The Ultimate Guide to Testing with Prisma: CI Pipelines

目次

はじめに

このシリーズの終わりに差し掛かり、これまでの4つの記事で何を達成したか、改めて考えてみましょう。あなたは

  1. Prisma Client をモック化した
  2. 単体テストについて学び、記述した
  3. 結合テストについて学び、記述した
  4. エンドツーエンドテストについて学び、記述した

あなたが学んだテスト戦略と概念は、既存のコードベースで、新しい変更が期待通りに機能することを確認し、コードを記述することを可能にするでしょう。

この安心感は、特に大規模なチームにおいて非常に重要です。しかし、あなたが学んだことには一つ課題があります。それは、変更を加えるたびにテストを手動で実行する必要があるということです。

この記事では、テストの実行を自動化する方法を学び、プライマリブランチへのプルリクエストが行われると、コードベースへの変更が自動的にテストされるようにします。

継続的インテグレーションパイプラインとは?

継続的インテグレーションパイプラインとは、ソフトウェアの新しいバージョンを公開する前に完了する必要がある一連のステップを記述したものです。おそらく、継続的インテグレーション継続的デプロイメントを指すCI/CDという頭字語を目にしたり、耳にしたことがあるでしょう。通常、これらの個々の概念は、今回検討するようなパイプラインを通じて処理されます。

この記事では、コードのビルド、テスト、そして最終的なマージを行うCIの部分に焦点を当てます。

パイプラインをセットアップできる技術はたくさんあり、どれを使用するかは、多くの場合、使用しているスタックによって異なります。例えば、以下の環境でパイプラインをセットアップできます。

  • Jenkins
  • CircleCI
  • GitLab
  • AWS Codepipeline
  • など、他にも多数...

この記事では、GitHub Actions を使用してパイプラインを定義する方法を学びます。これにより、プライマリブランチへのプルリクエストを作成するたびに、コード変更に対してパイプラインを実行するように設定できます。

使用する技術

前提条件

前提知識

以下の手順を進める上で、次の知識があると役立ちます

  • Git の基本的な知識
  • Docker の基本的な理解

開発環境

提供された例に沿って進めるには、以下がインストールされている必要があります。

  • Node.js がインストールされていること
  • 任意のコードエディタ (VSCode を推奨)
  • Git がインストールされていること
  • pnpm がインストールされていること
  • Docker がインストールされていること

このシリーズでは、この GitHub リポジトリを多用します。必ずリポジトリをクローンしてください。

リポジトリのクローン

ターミナルで、プロジェクトを保存しているディレクトリに移動してください。そのディレクトリで以下のコマンドを実行します。

上記のコマンドは、プロジェクトを testing_mono_repo という名前のフォルダにクローンします。このリポジトリのデフォルトブランチは main です。

前回の記事からのエンドツーエンドテストの完全なセットアップを含む e2e-tests ブランチに切り替える必要があります。

リポジトリをクローンし、正しいブランチをチェックアウトしたら、プロジェクトをセットアップするためにいくつかの手順が必要です。

まず、node_modules をインストールします。

次に、プロジェクトのルートに .env ファイルを作成します。

その新しいファイルに以下の変数を追加します。

.env ファイルには、以下の変数が追加されました。

  • API_SECRET: 認証サービスがパスワードを暗号化するために使用する秘密鍵を提供します。実際のアプリケーションでは、この値は数字と英字を含む長いランダムな文字列に置き換える必要があります。
  • DATABASE_URL: データベースへのURLが含まれています。
  • VITE_API_URL: Express API のURL。

独自のGitHubリポジトリをセットアップ

GitHub Actions で実行するパイプラインの設定を開始するには、まず、プルリクエストを送信するための main ブランチを持つ独自の GitHub リポジトリが必要です。

GitHub のウェブサイトにアクセスし、アカウントにサインインしてください。

: GitHub アカウントをお持ちでない場合は、こちらで無料で作成できます。

サインインしたら、以下に示す New ボタンをクリックして、新しいリポジトリを作成します。

New repository button in GitHub

次のページでは、リポジトリに関する情報が求められます。以下のフィールドに入力し、ページ下部の Create repository ボタンをクリックしてください。

New repository form in GitHub

その後、新しいリポジトリのホームページに移動します。上部には、リポジトリの URL をコピーできるテキストフィールドがあります。コピーアイコンをクリックして URL をコピーしてください。

New repository url in GitHub

新しい GitHub リポジトリの URL が手に入ったので、ターミナルでコードベースのルートディレクトリに移動し、次のコマンドでプロジェクトの origin を新しいリポジトリを指すように変更します(2行目にコピーした URL を必ず挿入してください)。

e2e-tests ブランチの進捗を基に進めるため、そのブランチを main とみなします。e2e-testsmain にマージしてください。

最後に、プロジェクトを新しいリポジトリにプッシュします。

ワークフローのセットアップ

これで、変更をプッシュできるリポジトリの準備ができました。次の目標は、既に作成した main ブランチに対してプルリクエストが作成または更新されるたびに、一連のタスクをトリガーすることです。

GitHub を使用する場合、これらのステップを定義するために ワークフロー ファイルを作成できます。これらのファイルは、プロジェクトのルートディレクトリ内の .github/workflows フォルダ内に作成する必要があります。

プロジェクトに .github という名前の新しいフォルダを作成します。

.github/workflows フォルダ内に、テストワークフローを定義する新しいファイル test.yml を作成します。

このファイル内で、GitHub Actions がプロジェクトを準備し、テストスイートを実行するために取るべき手順を指定します。

このワークフローを開始するために、name 属性を使用してワークフローに名前を付けます。

ワークフローはGitHub内で 'Tests' として表示されるようになります。

次に、このワークフローを、リポジトリの main ブランチに対してプルリクエストが作成された場合にのみ実行されるように構成します。これを実現するために、on キーワードに以下のオプションを追加します。

: インデントに注意してください。YAMLファイルではインデントが非常に重要であり、不適切なインデントはファイルの失敗につながります。

これでワークフローに名前を付け、main ブランチに対してプルリクエストが作成または更新された場合にのみ実行されるように設定しました。次に、単体テストを実行するジョブの定義を開始します。

: ワークフローファイルには、ワークフローの実行方法、内容などを変更するための非常に多くのオプションがあります。完全なリストについては、GitHub のドキュメントを確認してください。

単体テストジョブの追加

ワークフロー内で特定のタスクに関連する一連の命令(ステップと呼ばれる)を定義するには、job キーワードを使用します。各ジョブは、設定した隔離された環境内で一連のステップを実行します。

.github/workflows/tests.yml ファイルに jobs セクションを追加し、unit-tests という名前のジョブを指定します。

前述したように、各ジョブは独自の環境で実行されます。ジョブを実行するには、そのジョブが実行されるマシンの種類を指定する必要があります。

runs-on キーワードを使用して、ジョブが ubuntu-latest マシンで実行されるように指定します。

単体テストジョブを設定するために定義する最後のセクションは steps セクションです。ここでは、ジョブが単体テストを実行するために取るべき一連の手順を定義します。

unit-tests ジョブに以下を追加します。

これは、1つのステップを持つ steps セクションを定義します。その1つのステップは、actions/checkout という名前の事前にビルドされたアクションの v3 を使用し、GitHub リポジトリをチェックアウトして、ジョブ内で操作できるようにします。

: アクションとは、ワークフロー内で使用できる一連の個別のステップです。再利用可能な一連のステップを1つのファイルにまとめるのに役立ちます。

次に、仮想環境に Node.js をインストールし、PNPM をインストールし、リポジトリのパッケージをインストールする一連のステップを定義する必要があります。

これらのステップは作成するすべてのテストジョブで必要となるため、再利用可能なカスタムアクションとして定義します。

.github ディレクトリ内に actions という名前の新しいフォルダを、そして .github/actions フォルダ内に build フォルダを作成します。

次に、.github/actions/build 内に action.yml という名前のファイルを作成します。

そのファイル内に、以下を貼り付けます。

このファイルは複合アクションを定義しており、このアクションで定義されたstepsをジョブ内で使用できます。

上記で追加したステップは以下のことを行います。

  1. 仮想環境にPNPMをセットアップする
  2. 仮想環境にNode.jsをセットアップする
  3. リポジトリで pnpm install を実行し、node_modules をインストールする

この再利用可能なアクションが定義されたので、メインのワークフローファイルで使用できます。

.github/workflows/tests.yml に戻り、uses キーワードを使用してそのカスタムアクションを使用します。

この時点で、ジョブはリポジトリをチェックアウトし、仮想環境をセットアップし、node_modules をインストールします。残るは、実際にテストを実行することだけです。

最後に、単体テストを実行するために pnpm test:backend:unit を実行するステップを追加します。

: この新しいステップに name キーワードを使用して 'Run tests' と名前を付け、run キーワードを使用して任意のコマンドを実行したことに注目してください。

このジョブはこれで完了し、テストの準備ができました。テストするには、まずこのコードをリポジトリの main ブランチにプッシュします。

ワークフローは main ブランチで定義されました。ただし、ワークフローがトリガーされるのは、そのブランチに対してプルリクエストを送信した場合のみです。

new-branch という名前の新しいブランチを作成します。

その新しいブランチ内で、backend/src/index.ts ファイルにコメントを追加するなどの軽微な変更を行います。

次に、これらの変更をリモートリポジトリにコミットしてプッシュします。リポジトリは現在 new-branch ブランチを認識していないため、origin がこれらの変更を処理するために new-branch という名前のブランチを使用するよう指定する必要があります。

新しいブランチがリモートリポジトリで利用可能になりました。このブランチを main ブランチにマージするためのプルリクエストを作成します。

ブラウザでリポジトリにアクセスします。ページ上部の Pull requests タブに、new-branch に最近プッシュがあったため、Compare & pull request ボタンが表示されているはずです。

GitHub PR tab

そのボタンをクリックしてプルリクエストを開きます。新しいページに移動するはずです。その新しいページで、Create pull request ボタンをクリックしてプルリクエストを開いてください。

GitHub create PR page

プルリクエストを開くと、Merge pull request ボタンの上に、Tests ジョブが実行中であることを示す黄色のボックスが表示されるはずです。

PR page with unit tests running in a job.

Details ボタンをクリックすると、各ステップの実行状況とそのコンソール出力が表示されるはずです。

ジョブが完了すると、ワークフロー内のチェックが合格したかどうかが通知されます。

PR page with successful tests.

これで単体テストジョブが完了したので、次は結合テストを実行するジョブの作成に進みます。

: このプルリクエストはまだマージしないでください!この記事の残りの部分でこのプルリクエストを再利用します。

結合テストジョブの追加

結合テストを実行するプロセスは、単体テストを実行した方法と非常によく似ています。このジョブとの違いは、結合テストがテストデータベースと環境変数に依存していることです。このセクションでは、それらをセットアップし、テストを実行するジョブを定義します。

変更を開始する前に、再度リポジトリの main ブランチをチェックアウトする必要があります。

まず、unit-tests ジョブをコピーして、integration-tests という名前の新しいジョブを作成します。また、このジョブの最後のステップで pnpm test:backend:unitpnpm test:backend:int に置き換えます。

これで、テストを実行するために必要なほとんどの要素が揃っていますが、このままワークフローを実行すると、scripts/run-integration.sh ファイルが実行されます。このスクリプトは Docker Compose を使用してテストデータベースを起動します。

GitHub Actions が使用する仮想環境には、デフォルトで Docker Compose が含まれていません。これを機能させるには、Docker Compose を環境にインストールする別のカスタムアクションをセットアップします。

.github/actions 内に docker-compose という名前の新しいフォルダを作成し、その中に action.yml という名前のファイルを作成します。

このアクションは2つのことを行う必要があります。

  1. Docker Compose プラグインを仮想環境にダウンロードする
  2. プラグインを実行可能にし、docker-compose コマンドが使用できるようにする

これらのタスクを処理するために、.github/actions/docker-compose/action.yml に以下を貼り付けます。

上記のコードスニペットの最初のステップは、Docker Compose プラグインのソースを仮想環境の /usr/local/bin/docker-compose にダウンロードします。その後、chmod を使用して、このソースを実行可能ファイルとして設定します。

カスタムアクションが完成したら、.github/workflows/tests.ymlintegration-tests ジョブに、テストが実行されるステップの直前に追加します。

このテストに必要な最後のものは、一連の環境変数です。アプリケーションが期待する環境変数は以下のとおりです。

  • DATABASE_URL: データベースのURL
  • API_SECRET: JWT の署名に使用される認証シークレット
  • VITE_API_URL: Express API のURL

これらは env キーワードを使用して仮想環境に追加できます。環境変数は、ワークフローレベルで追加してすべてのジョブに適用するか、特定のジョブに追加することができます。今回は、各ジョブで変数が利用できるように、ワークフローレベルで追加します。

: 通常は、必要な環境変数を各ジョブに個別に公開することがベストプラクティスです。この記事では、簡潔にするためにすべてのジョブに変数を公開します。

ワークフローに env キーを追加し、必要な3つの変数を定義します。

この時点で、これらの変更をコミットして main ブランチにプッシュし、ワークフローに変更を公開できます。

次に、ワークフローの新しい実行をトリガーするために、以下を実行してこれらの変更を new-branch ブランチにマージします。

: git merge main のステップで、ターミナルでエディタが開きます。:qa と入力し enter を押してそのエディタを終了してください。

このジョブは、Docker Compose のインストール、データベースの起動、そしてすべてのテストの実行が必要なため、単体テストのジョブよりもかなり時間がかかります。

ジョブが完了すると、以下の成功メッセージが表示されるはずです。

Successfull integration and unit tests.

エンドツーエンドテストジョブの追加

これで単体テストと結合テストがワークフローで実行されるようになったので、最後に定義するテストはエンドツーエンドテストです。

まず、再度 main ブランチをチェックアウトし、ワークフローファイルを変更します。

前のセクションと同様に、integration-tests ジョブの内容を新しいジョブ e2e-tests にコピーし、pnpm backend:tests:intpnpm test:e2e に置き換えます。

新しいジョブをコミットする前に、いくつか行うべきことがあります。

  • 仮想環境に Playwright とそのテストブラウザをインストールする
  • scripts/run-e2e.sh を更新

このジョブで Docker Compose をインストールするステップの直後に、Playwright をダウンロードし、プロジェクトの e2e フォルダにそのテストブラウザをインストールする2つの新しいステップを追加します。

Playwright をインストールする際に Playwright が使用する2つの新しい環境変数を env セクションに追加する必要もあります。

これで、ワークフローが実行されると、Playwright が適切にインストールおよび設定され、テストが実行できるようになります。

次に変更すべきは、scripts/run-e2e.sh スクリプトがエンドツーエンドテストを実行する方法です。

現在、エンドツーエンドテストの実行が完了すると、スクリプトは npx playwright show-report を使用して結果レポートを自動的に提供します。CI 環境では、手動でキャンセルされるまでジョブが無限に実行されてしまうため、これを避けたいです。

その行をスクリプトから削除します。

その問題が解決したので、これで変更を main にプッシュし、それらの変更を new-branch ブランチにマージする準備ができました。

ブラウザでプルリクエストに戻ると、現在3つのジョブがチェックで実行されているのが確認できるはずです。

新しいジョブは、Docker Compose と Playwright のブラウザをダウンロードし、データベースを起動し、すべてのテストを実行する必要があるため、完了するまでに時間がかかります。

ジョブが完了すると、成功したテストの完了リストが表示されるはずです。

A complete set of successful jobs

まとめと最終的な考察

この記事では、継続的インテグレーションについて学びました。より具体的には、以下のことを学びました。

  • 継続的インテグレーションとは何か
  • それがプロジェクトで役立つ理由
  • GitHub Actions を使用して CI パイプラインをセットアップする方法

最終的に、main ブランチに対するプルリクエストに関連付けられた任意のブランチに対して、テストスイート全体を自動的に実行する CI パイプラインが完成しました。

これは強力であり、各プルリクエストにチェックを設定して、関連するブランチの変更が意図通りに機能することを確認できます。GitHub のセキュリティ設定を使用すると、これらのチェックが成功しなかった場合に main へのマージを防止することもできます。

このシリーズを通して、アプリケーションに対して実行できるさまざまな種類のテスト、Prisma を使用してデータベースと連携する関数やアプリケーションに対するテストの記述方法、そしてプロジェクトでそれらのテストを活用する方法について学びました。

このシリーズで扱われた内容についてご質問がありましたら、Twitterでお気軽にお問い合わせください。

次の投稿をお見逃しなく!

Prisma ニュースレターに登録

© . All rights reserved.