📝

CI/CDパイプラインでのテスト自動化(開発日記 No.031)

に公開

関連リンク

Diary-Converterのテスト環境整備とCI/CD自動化 (Issue #4)

はじめに

昨日はZenn公開用記事フォーマットの改善に取り組み、メッセージボックスの追加やリンクURL、記事タイトルの問題を修正しました。本日は、開発プロセスをより堅牢にするため、Diary-ConverterプロジェクトのIssue #4「testsディレクトリの整理とCI/CDパイプラインでのテスト自動化」の解決に焦点を当てます。

背景と目的

プロジェクトが成長するにつれて、テストコードの管理が煩雑になり、手動でのテスト実行も手間がかかるようになってきました。特に、私の開発環境であるWSL2上のUbuntuでは、ホスト環境へのツールインストールを最小限に抑えたいため、Dockerコンテナを活用したテスト実行環境の整備が急務でした。

今回の目的は、以下の3点です。

  1. testsディレクトリを整理してメンテナンス性を向上させる。
  2. GitHub Actionsを用いたCI/CDパイプラインでテストを自動化する。
  3. Docker環境でのテスト実行を安定させる。

これらを通じて、開発効率とコード品質を高めることを目指します。

検討内容

課題の整理

まず現状を調査したところ、以下の課題が明らかになりました。

  1. testsディレクトリの乱雑さ: testsディレクトリ内のファイル構成が場当たり的で、古いパス参照も残っており、どこに何があるか分かりにくい状態でした。
  2. CI/CDでのテスト未実行: CI/CDパイプラインが設定されておらず、コード変更時の自動テストが行われていませんでした。これにより、デグレの発見が遅れるリスクがありました。
  3. Dockerテストの不安定さ: Dockerコンテナを使ったテスト実行方法は存在するものの、設定に不備があり、安定して動作しない状態でした。

解決アプローチ

これらの課題に対し、以下のステップで改善を進めることにしました。

  1. testsディレクトリの再構築: testsディレクトリを機能(ユニット、統合、フィクスチャ、スクリプト)ごとに整理し、構造を明確にします。
  2. テストスクリプトの修正: テスト実行スクリプトを最新のプロジェクト構造に合わせて修正し、統一的な実行方法を提供します。
  3. GitHub Actionsワークフローの導入: GitHub Actionsワークフローを作成し、プッシュやプルリクエスト時に自動でテストが実行されるようにします。
  4. Docker環境の改善: Dockerfileや関連スクリプトを見直し、Docker環境でのテスト実行を確実なものにします。

実装内容

上記のアプローチに基づき、具体的な実装を行いました。

変更点1: testsディレクトリの整理

まず、testsディレクトリを以下のように再構築しました。

tests/
├── fixtures/         # テスト用のフィクスチャ(入力ファイルやテンプレートなど)
├── integration/      # 統合テスト (test_end_to_end.py)
├── output/           # テスト出力ディレクトリ
├── scripts/          # テスト実行スクリプト (run_*.sh)
└── unit/             # ユニットテスト (test_diary_converter.py)

各ディレクトリに対応するテストファイルやスクリプトを配置し、役割を明確にしました。これにより、テストコードの見通しが大幅に改善され、メンテナンス性が向上しました。

変更点2: CI/CDパイプラインの設定

GitHub Actionsワークフローを2つ設定しました。

  1. Diary-Converter/.github/workflows/test.yml: Diary-Converterリポジトリ本体用のテスト自動実行ワークフロー。
  2. Docs/.github/workflows/diary-convert.yml: Docsリポジトリ用のワークフローですが、こちらでもDiary-Converterのテストを実行するようにし、ドキュメント生成プロセスとの連携も考慮しました。

これにより、コードがリポジトリにプッシュされるたびに、自動でテストが実行される体制が整いました。

変更点3: READMEの更新

新しいテストディレクトリ構造と実行方法(tests/scripts/以下のシェルスクリプトを使用)について、READMEファイルを更新しました。

変更点4: Dockerテストのエラー修正

ローカルでの動作確認を進める中で、Dockerテストでいくつかの問題が発生しました。

エラー1: docker-entrypoint.sh が見つからない

最初の実行では以下のエラーが発生しました。

Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: error during container init: exec: "/app/docker-entrypoint.sh": stat /app/docker-entrypoint.sh: no such file or directory: unknown

これは、Dockerfile内で docker-entrypoint.sh ファイルがコンテナイメージにコピーされていなかったことが原因でした。Dockerfileに以下の行を追加し、実行権限を付与することで解決しました。

# Dockerfileの修正箇所
COPY docker-entrypoint.sh /app/
RUN chmod +x /app/docker-entrypoint.sh

エラー2: ModuleNotFoundError

上記エラーを修正後、再度テストを実行すると、今度はPythonのモジュールが見つからないというエラーが発生しました。

/usr/local/bin/python: Error while finding module specification for 'diary_converter.diary_converter' (ModuleNotFoundError: No module named 'diary_converter')

これは、Dockerコンテナ内でPythonが src ディレクトリをモジュールパスとして認識できていないことが原因でした。docker-entrypoint.sh を以下のように修正しました。

#!/bin/bash
set -e

# (引数チェックなどは省略)

# 入力ファイルと出力ファイルのパスを設定
INPUT_FILE="$1"
OUTPUT_FILE="$2"
shift 2

# Pythonパスを設定 (修正点)
export PYTHONPATH=/app/src:$PYTHONPATH

# モジュールの存在を確認 (デバッグ用に追加)
echo "Pythonモジュールの確認:"
python -c "import sys; print(sys.path)"
python -c "import os; print(os.listdir('/app/src'))"

# 残りの引数をそのまま渡し、モジュールとして実行 (修正点)
cd /app
python -m src.diary_converter.diary_converter "$INPUT_FILE" "$OUTPUT_FILE" "$@"

主な変更点は、PYTHONPATH/app/src を追加したことと、python -m src.diary_converter.diary_converter ... のようにモジュールとしてスクリプトを実行するようにしたことです。

その他の修正

  • docker-compose.ymlの修正: version 属性が古い形式であるという警告が出ていたため、この属性を削除しました。
  • orphanコンテナの削除: 以前のテスト実行で残っていた不要なコンテナを削除するために、docker-compose down --remove-orphans コマンドを使用するようにテストスクリプトや手順を案内しました。

技術的なポイント

今回の実装における技術的なポイントは以下の通りです。

  • Docker環境でのPythonパス設定: PYTHONPATH環境変数を適切に設定することで、コンテナ内で src ディレクトリ以下のモジュールを正しくインポートできるようにしました。python -m を使ってモジュールとしてスクリプトを実行することも重要でした。
  • DockerfileのCOPYと権限: 必要なスクリプト (docker-entrypoint.sh) を COPY 命令でコンテナイメージに含め、RUN chmod +x で実行権限を付与することが、コンテナ起動時のエラーを防ぐ鍵となりました。
  • GitHub Actionsによるテスト自動化: ワークフローファイルをリポジトリに配置するだけで、コード変更をトリガーとしたテスト実行が自動化され、開発サイクルの効率化と品質担保に繋がります。異なるリポジトリ (Diary-ConverterDocs) で連携してテストを実行する設定も行いました。
  • テストディレクトリの構造化: テストの種類(ユニット、統合)や目的(フィクスチャ、スクリプト)に応じてディレクトリを分けることで、テストコードの可読性とメンテナンス性が向上しました。

所感

Docker環境でのテスト実行は、当初想定していたよりも多くのエラーに遭遇しました。特に、ファイルパスやPythonのモジュールパスに関する問題は、コンテナ環境特有の注意点であり、デバッグに時間を要しました。しかし、エラーメッセージを注意深く読み解き、一つずつ原因を特定して修正していくことで、最終的に安定したテスト環境を構築できました。

testsディレクトリの整理やCI/CDパイプラインの導入は、今後の開発効率とコード品質の向上に大きく貢献すると感じています。特に、自動テストによってデグレを早期に発見できる体制が整ったことは、安心して開発を進める上で非常に重要です。WSL2環境に余計なツールをインストールせずに済む点も、当初の目的通り達成できました。

今後の課題

今回の対応でテスト環境の基盤は整いましたが、今後は以下の課題に取り組む予定です。

  1. テストカバレッジの向上: 現在のテストがカバーしきれていないコード領域を特定し、テストケースを追加する。
  2. テストの高速化: テスト実行時間を短縮するための最適化を検討する(例: 並列実行、不要な処理の削減)。
  3. エラーハンドリングのテスト: 様々な異常系パターンに対するテストを追加し、堅牢性を高める。
  4. CI/CDパイプラインの最適化: ワークフローの実行効率改善や、通知機能の強化などを検討する。

まとめ

今回は、Diary-ConverterプロジェクトのIssue #4に取り組み、testsディレクトリの整理、CI/CDパイプラインによるテスト自動化、Dockerテスト環境の安定化を実現しました。段階的なエラー修正を経て、より堅牢で効率的な開発プロセスを構築するための重要な一歩となりました。今後は、テストカバレッジの向上など、さらなる品質改善を進めていきます。

GitHubで編集を提案

Discussion