演習:本格テストパイプライン構築
ストーリー
「ここまでの知識を総動員して、本番に使える テスト自動化パイプラインを構築しよう」
木村先輩が要件を書き出した。
「マトリクスビルド、キャッシュ、シークレット、アーティファクト。 全部組み合わせて、実戦レベルのCIパイプラインを作ってくれ。 これが完成すれば、うちのチームのデプロイ品質は 飛躍的に向上するはずだ」
演習の概要
Node.js + PostgreSQLのWebアプリケーションに対して、本格的なテスト自動化パイプラインを構築してください。
プロジェクト構成
webapp/
├── .github/
│ └── workflows/
│ └── ci.yml ← 今回作成
├── src/
│ ├── index.ts
│ ├── routes/
│ ├── services/
│ └── repositories/
├── tests/
│ ├── unit/
│ │ ├── services.test.ts
│ │ └── validators.test.ts
│ ├── integration/
│ │ └── api.test.ts
│ └── e2e/
│ └── app.e2e.test.ts
├── package.json
├── tsconfig.json
├── jest.config.ts
├── Dockerfile
└── docker-compose.yml
課題1: マルチバージョンテストパイプライン
Node.js 18と20でテストを実行するマトリクスビルドを構築してください。
要件
- マトリクス: Node.js 18, 20
- キャッシュ: npm キャッシュを使用
- ステップ: checkout → setup-node → npm ci → lint → typecheck → 単体テスト
- fail-fast: false
- タイムアウト: 15分
yaml
name: CI Pipeline
on:
pull_request:
branches: [ main ]
push:
branches: [ main ]
permissions:
contents: read
jobs:
lint-and-unit-test:
name: Lint & Unit Test (Node ${{ matrix.node-version }})
runs-on: ubuntu-latest
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
node-version: [18, 20]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run ESLint
run: npm run lint
- name: Type check
run: npm run typecheck
- name: Run unit tests
run: npm run test:unit -- --coverage
- name: Upload coverage report
if: matrix.node-version == 20
uses: actions/upload-artifact@v4
with:
name: coverage-report
path: coverage/
retention-days: 7課題2: 結合テスト(サービスコンテナ付き)
PostgreSQLサービスコンテナを使った結合テストを追加してください。
要件
- 課題1のテストが成功した後に実行(needs)
- PostgreSQL 16 のサービスコンテナを使用
- ヘルスチェック設定を含む
- 環境変数 DATABASE_URL でDB接続先を指定
yaml
integration-test:
name: Integration Test
needs: lint-and-unit-test
runs-on: ubuntu-latest
timeout-minutes: 20
services:
postgres:
image: postgres:16
env:
POSTGRES_DB: test_db
POSTGRES_USER: test_user
POSTGRES_PASSWORD: test_password
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run database migrations
env:
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/test_db
run: npm run db:migrate
- name: Seed test data
env:
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/test_db
run: npm run db:seed
- name: Run integration tests
env:
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/test_db
NODE_ENV: test
run: npm run test:integration
- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: integration-test-results
path: test-results/
retention-days: 7課題3: ビルドとDockerイメージ作成
結合テスト成功後にアプリケーションをビルドし、Dockerイメージを作成してください。
要件
- 結合テスト成功後に実行
- npm run build でアプリをビルド
- Docker イメージをビルド(pushはしない)
- ビルド成果物をアーティファクトとして保存
- バージョン情報をジョブ出力として公開
yaml
build:
name: Build Application
needs: integration-test
runs-on: ubuntu-latest
timeout-minutes: 15
outputs:
version: ${{ steps.version.outputs.version }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build application
run: npm run build
- name: Get version
id: version
run: |
VERSION=$(node -p "require('./package.json').version")
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "Application version: $VERSION"
- name: Build Docker image
run: |
docker build \
--tag webapp:${{ steps.version.outputs.version }} \
--tag webapp:${{ github.sha }} \
--label "org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}" \
--label "org.opencontainers.image.revision=${{ github.sha }}" \
.
- name: Upload build artifact
uses: actions/upload-artifact@v4
with:
name: production-build
path: dist/
retention-days: 3
- name: Build summary
run: |
echo "## Build Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Item | Value |" >> $GITHUB_STEP_SUMMARY
echo "|------|-------|" >> $GITHUB_STEP_SUMMARY
echo "| Version | ${{ steps.version.outputs.version }} |" >> $GITHUB_STEP_SUMMARY
echo "| Commit | ${{ github.sha }} |" >> $GITHUB_STEP_SUMMARY
echo "| Docker Image | webapp:${{ steps.version.outputs.version }} |" >> $GITHUB_STEP_SUMMARY課題4: 通知ジョブの追加
パイプライン全体の結果を通知するジョブを追加してください。
要件
- buildジョブの完了後に実行
- 常に実行(
if: always()) - 成功/失敗に応じたメッセージをJob Summaryに出力
- 失敗時はバージョン情報やコミットSHAを含むデバッグ情報を出力
yaml
notify:
name: Pipeline Result
needs: [lint-and-unit-test, integration-test, build]
if: always()
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Check pipeline result
run: |
echo "## Pipeline Result" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [ "${{ needs.lint-and-unit-test.result }}" == "success" ] && \
[ "${{ needs.integration-test.result }}" == "success" ] && \
[ "${{ needs.build.result }}" == "success" ]; then
echo "### All checks passed!" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Stage | Result |" >> $GITHUB_STEP_SUMMARY
echo "|-------|--------|" >> $GITHUB_STEP_SUMMARY
echo "| Lint & Unit Test | ${{ needs.lint-and-unit-test.result }} |" >> $GITHUB_STEP_SUMMARY
echo "| Integration Test | ${{ needs.integration-test.result }} |" >> $GITHUB_STEP_SUMMARY
echo "| Build | ${{ needs.build.result }} |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Version: ${{ needs.build.outputs.version }}" >> $GITHUB_STEP_SUMMARY
else
echo "### Pipeline failed!" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Stage | Result |" >> $GITHUB_STEP_SUMMARY
echo "|-------|--------|" >> $GITHUB_STEP_SUMMARY
echo "| Lint & Unit Test | ${{ needs.lint-and-unit-test.result }} |" >> $GITHUB_STEP_SUMMARY
echo "| Integration Test | ${{ needs.integration-test.result }} |" >> $GITHUB_STEP_SUMMARY
echo "| Build | ${{ needs.build.result }} |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Debug Info:**" >> $GITHUB_STEP_SUMMARY
echo "- Commit: ${{ github.sha }}" >> $GITHUB_STEP_SUMMARY
echo "- Actor: ${{ github.actor }}" >> $GITHUB_STEP_SUMMARY
echo "- Branch: ${{ github.ref_name }}" >> $GITHUB_STEP_SUMMARY
exit 1
fi達成度チェック
| 課題 | 内容 | 完了 |
|---|---|---|
| 課題1 | マルチバージョンテスト(マトリクスビルド) | [ ] |
| 課題2 | 結合テスト(サービスコンテナ付き) | [ ] |
| 課題3 | ビルドとDockerイメージ作成 | [ ] |
| 課題4 | 通知ジョブの追加 | [ ] |
まとめ
| ポイント | 内容 |
|---|---|
| マトリクスビルド | 複数Node.jsバージョンで並列テスト |
| サービスコンテナ | PostgreSQLを使った結合テスト |
| アーティファクト | ビルド成果物の保存とジョブ間受け渡し |
| 通知 | パイプライン結果のサマリー出力 |
チェックリスト
- マトリクスビルドでマルチバージョンテストを構成できた
- サービスコンテナを使った結合テストを実装できた
- Dockerイメージのビルドとアーティファクト保存を実装できた
- パイプライン全体の結果通知を実装できた
- 完成したパイプラインの実行フローを説明できる
次のステップへ
演習が完了したら、Step 3 のチェックポイントクイズに挑戦しましょう。
推定所要時間: 90分