2023年3月24日

Prismaでのテストの究極ガイド:CIパイプライン

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

The Ultimate Guide to Testing with Prisma: CI Pipelines

目次

はじめに

このシリーズの終わりに近づき、一歩下がって、過去4つの記事で達成したことを考えてみてください。あなたは

  1. Prisma Clientをモックしました
  2. ユニットテストについて学び、記述しました
  3. 統合テストについて学び、記述しました
  4. エンドツーエンドテストについて学び、記述しました

あなたが学んだテスト戦略と概念により、既存のコードベースでコードを記述し、新しい変更が期待どおりに動作することを確認できます。

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

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

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

継続的インテグレーションパイプラインは、ソフトウェアの新しいバージョンを公開する前に完了する必要がある一連のステップを記述します。おそらく、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 Webサイトにアクセスし、アカウントにサインインします。

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

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

New repository button in GitHub

次のページで、リポジトリに関するいくつかの情報を求められます。以下に示すフィールドに入力し、ページ下部のリポジトリの作成ボタンをクリックします。

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リポジトリをチェックアウトして、ジョブ内で操作できるようにします。

アクションは、ワークフロー内で使用できる個々のステップのセットです。再利用可能なステップのセットを単一のファイルに分割するのに役立ちます。

次に、仮想環境に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ブランチを認識していないため、これらの変更を処理するためにoriginnew-branchという名前のブランチを使用する必要があることを指定する必要があります。

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

ブラウザでリポジトリに移動します。ページ上部のプルリクエストタブに、new-branchが最近プッシュされたため、比較とプルリクエストボタンが表示されるはずです。

GitHub PR tab

そのボタンをクリックしてプルリクエストを開きます。新しいページに移動します。その新しいページで、プルリクエストの作成ボタンをクリックしてプルリクエストを開きます。

GitHub create PR page

プルリクエストを開くと、プルリクエストのマージボタンの上に黄色のボックスが表示され、Testsジョブが実行されていることが示されます。

PR page with unit tests running in a job.

詳細ボタンをクリックすると、各ステップがコンソール出力とともに実行されていることが表示されます。

ジョブが完了すると、ワークフローのチェックが成功したか失敗したかが通知されます。

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/actionsdocker-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ステップでは、ターミナルでエディターに入ります。:qaenterを押して、そのエディターを終了します。

このジョブは、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つの新しいステップを追加します。

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

これで、ワークフローが実行されると、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ニュースレターにサインアップ