継続的インテグレーション(CI)とは、さまざまな作成者からのコード変更を安全に中央リポジトリに統合するプロセスを指します。この記事では、CIパイプラインとは何か、CIパイプラインを構成する方法、およびそのパイプラインを使用してテストを自動化する方法について詳しく学びます。
目次
はじめに
このシリーズの終わりに近づき、一歩下がって、過去4つの記事で達成したことを考えてみてください。あなたは
- Prisma Clientをモックしました
- ユニットテストについて学び、記述しました
- 統合テストについて学び、記述しました
- エンドツーエンドテストについて学び、記述しました
あなたが学んだテスト戦略と概念により、既存のコードベースでコードを記述し、新しい変更が期待どおりに動作することを確認できます。
この安心感は、特に大規模なチームでは非常に重要です。ただし、あなたが学んだことには、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アカウントをお持ちでない場合は、こちらで無料アカウントを作成できます。
サインインしたら、以下に示す新規ボタンをクリックして、新しいリポジトリを作成します。

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

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

これで、新しいGitHubリポジトリへのURLができました。ターミナルでコードベースのルートディレクトリに移動し、次のコマンドを使用してプロジェクトのoriginを新しいリポジトリを指すように変更します(2行目にコピーしたURLを必ず挿入してください)。
e2e-tests
ブランチでの進捗状況から作業するため、そのブランチはmain
と見なされる必要があります。e2e-tests
をmain
にマージします。
最後に、プロジェクトを新しいリポジトリにプッシュします。
ワークフローの設定
これで、変更をプッシュできるリポジトリが設定されました。次の目標は、すでに作成した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
を使用できます。
上記で追加したステップは、次のことを行います。
- 仮想環境にPNPMを設定します
- 仮想環境にNode.jsを設定します
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
ブランチにマージするプルリクエストを作成します。
ブラウザでリポジトリに移動します。ページ上部のプルリクエストタブに、new-branch
が最近プッシュされたため、比較とプルリクエストボタンが表示されるはずです。

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

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

詳細ボタンをクリックすると、各ステップがコンソール出力とともに実行されていることが表示されます。
ジョブが完了すると、ワークフローのチェックが成功したか失敗したかが通知されます。

これでユニットテストジョブが完了したので、統合テストを実行するジョブの作成に進みます。
注:まだこのプルリクエストをマージしないでください!この記事の残りの部分全体でこのプルリクエストを再利用します。
統合テストジョブの追加
統合テストを実行するプロセスは、ユニットテストの実行方法と非常によく似ています。このジョブの違いは、統合テストがテストデータベースと環境変数に依存していることです。このセクションでは、それらをセットアップし、テストを実行するジョブを定義します。
変更を開始する前に、リポジトリのmain
ブランチを再度チェックアウトする必要があります。
まず、unit-tests
ジョブをコピーして、integration-tests
という名前の新しいジョブにコピーします。また、このジョブの最後のステップで、pnpm test:backend:unit
をpnpm test:backend:int
に置き換えます。
これで、テストを実行するために必要なほとんどのものが揃いましたが、ワークフローをそのまま実行すると、scripts/run-integration.sh
ファイルがトリガーされて実行されます。そのスクリプトは、Docker Composeを使用してテストデータベースを起動します。
GitHub Actionsが使用する仮想環境には、デフォルトでDocker Composeが付属していません。これを機能させるには、Docker Composeを環境にインストールする別のカスタムアクションを設定します。
.github/actions
にdocker-compose
という名前の新しいフォルダーを作成し、その中にaction.yml
という名前のファイルを作成します。
このアクションは、次の2つのことを行う必要があります。
- Docker Composeプラグインを仮想環境にダウンロードする
docker-compose
コマンドを使用できるように、プラグインを実行可能にする
.github/actions/docker-compose/action.yml
に以下を貼り付けて、これらのタスクを処理します。
上記の最初のステップでは、Docker Composeプラグインソースを仮想環境の/usr/local/bin/docker-compose
にダウンロードします。次に、chmod
を使用して、このソースを実行可能ファイルとして設定します。
カスタムアクションが完了したら、.github/workflows/tests.yml
のintegration-tests
ジョブに、テストが実行されるステップの直前に追加します。
このテストに必要な最後のものは、環境変数のセットです。アプリケーションが期待する環境変数は次のとおりです。
DATABASE_URL
:データベースのURLAPI_SECRET
:JWTの署名に使用される認証シークレットVITE_API_URL
:Express APIのURL
これらの変数をenv
キーワードを使用して仮想環境に追加できます。環境変数はワークフローレベルで追加でき、すべてのジョブに適用されます。または特定のジョブに追加することもできます。ここでは、変数を各ジョブで使用できるように、ワークフローレベルで追加します。
注:通常は、必要な環境変数のみを個々のジョブに公開するのがベストプラクティスです。この記事では、簡略化のために変数はすべてのジョブに公開されます。
env
キーをワークフローに追加し、必要な3つの変数を定義します。
この時点で、これらの変更をmain
ブランチにコミットしてプッシュし、ワークフローへの変更を公開できます。
次に、次のコマンドを実行してnew-branch
ブランチにそれらの変更をマージし、ワークフローの新しい実行をトリガーします。
注:
git merge main
ステップでは、ターミナルでエディターに入ります。:qa
とenter
を押して、そのエディターを終了します。
このジョブは、Docker Composeをインストールし、データベースを起動してからすべてのテストを実行する必要があるため、ユニットテストジョブよりもかなり時間がかかります。
ジョブが完了すると、次の成功メッセージが表示されるはずです。

エンドツーエンドテストジョブの追加
これで、ユニットテストと統合テストがワークフローで実行されるようになったので、最後に定義するテストのセットはエンドツーエンドテストです。
まず、main
ブランチを再度チェックアウトして、ワークフローファイルを変更します。
前のセクションが始まった方法と同様に、integration-tests
ジョブの内容をe2e-tests
という名前の新しいジョブにコピーし、pnpm backend:tests:int
をpnpm 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のブラウザをダウンロードし、データベースを起動し、すべてのテストを実行する必要があるため、完了までに時間がかかります。
ジョブが完了すると、完了したテストの成功リストが表示されるはずです。

まとめと最終的な考え
この記事では、継続的インテグレーションについて学びました。具体的には、次のことを学びました。
- 継続的インテグレーションとは何か
- プロジェクトで役立つ理由
- GitHub Actionsを使用してCIパイプラインを設定する方法
最終的に、main
ブランチに対するプルリクエストに関連付けられたブランチに対して、テストスイート全体を自動的に実行するCIパイプラインを作成しました。
これは、各プルリクエストにチェックを設定して、関連するブランチの変更が意図したとおりに機能するようにするために強力です。GitHubのセキュリティ設定を使用すると、これらのチェックが成功しなかった場合にmain
へのマージを防ぐこともできます。
このシリーズ全体を通して、アプリケーションに対して実行できるさまざまな種類のテスト、Prismaを使用してデータベースと対話する関数やアプリに対してそれらのテストを作成する方法、およびそれらのテストをプロジェクトで活用する方法について学びました。
このシリーズで取り上げた内容について質問がある場合は、Twitterでお気軽にお問い合わせください。
次回の投稿をお見逃しなく!
Prismaニュースレターにサインアップ