継続的インテグレーション (CI) とは、複数の開発者によるコード変更を安全に中央リポジトリに統合するプロセスを指します。この記事では、CI パイプラインとは何か、CI パイプラインを構成する方法、およびそのパイプラインを使用してテストを自動化する方法について詳しく学びます。
目次
- 目次
- はじめに
- 前提条件
- 独自のGitHubリポジトリをセットアップ
- ワークフローのセットアップ
- 単体テストジョブの追加
- 結合テストジョブの追加
- エンドツーエンドテストジョブの追加
- まとめと最終的な考察
はじめに
このシリーズの終わりに差し掛かり、これまでの4つの記事で何を達成したか、改めて考えてみましょう。あなたは
- Prisma Client をモック化した
- 単体テストについて学び、記述した
- 結合テストについて学び、記述した
- エンドツーエンドテストについて学び、記述した
あなたが学んだテスト戦略と概念は、既存のコードベースで、新しい変更が期待通りに機能することを確認し、コードを記述することを可能にするでしょう。
この安心感は、特に大規模なチームにおいて非常に重要です。しかし、あなたが学んだことには一つ課題があります。それは、変更を加えるたびにテストを手動で実行する必要があるということです。
この記事では、テストの実行を自動化する方法を学び、プライマリブランチへのプルリクエストが行われると、コードベースへの変更が自動的にテストされるようにします。
継続的インテグレーションパイプラインとは?
継続的インテグレーションパイプラインとは、ソフトウェアの新しいバージョンを公開する前に完了する必要がある一連のステップを記述したものです。おそらく、継続的インテグレーションと継続的デプロイメントを指す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 ボタンをクリックして、新しいリポジトリを作成します。

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

その後、新しいリポジトリのホームページに移動します。上部には、リポジトリの 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 リポジトリをチェックアウトして、ジョブ内で操作できるようにします。
注: アクションとは、ワークフロー内で使用できる一連の個別のステップです。再利用可能な一連のステップを1つのファイルにまとめるのに役立ちます。
次に、仮想環境に 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
ブランチにマージするためのプルリクエストを作成します。
ブラウザでリポジトリにアクセスします。ページ上部の Pull requests タブに、new-branch
に最近プッシュがあったため、Compare & pull request ボタンが表示されているはずです。

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

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

Details ボタンをクリックすると、各ステップの実行状況とそのコンソール出力が表示されるはずです。
ジョブが完了すると、ワークフロー内のチェックが合格したかどうかが通知されます。

これで単体テストジョブが完了したので、次は結合テストを実行するジョブの作成に進みます。
注: このプルリクエストはまだマージしないでください!この記事の残りの部分でこのプルリクエストを再利用します。
結合テストジョブの追加
結合テストを実行するプロセスは、単体テストを実行した方法と非常によく似ています。このジョブとの違いは、結合テストがテストデータベースと環境変数に依存していることです。このセクションでは、それらをセットアップし、テストを実行するジョブを定義します。
変更を開始する前に、再度リポジトリの 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つの新しいステップを追加します。
Playwright をインストールする際に Playwright が使用する2つの新しい環境変数を env
セクションに追加する必要もあります。
これで、ワークフローが実行されると、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 ニュースレターに登録