9日目: ユニットテストの自動化とCodeBuildとの連携
はじめに:自動化された品質保証の第一歩
昨日は、CI/CDパイプラインにおいてテスト自動化がなぜ重要なのか、そしてテストピラミッドという概念について学びました。CI/CDの価値を最大限に引き出すためには、このテスト自動化をパイプラインに組み込むことが不可欠です。
テストピラミッドの土台をなすのがユニットテストです。アプリケーションの最小単位の機能を検証するユニットテストは、高速かつ安定して実行できるため、CI/CDパイプラインに最も適しています。Python開発においては、unittestやpytestといった優れたフレームワークが利用できます。
本記事では、このユニットテストをAWS CodeBuildと連携させ、ソースコードがプッシュされるたびに自動的にテストを実行し、その結果を確認する仕組みを構築します。これにより、コード変更が既存の機能に影響を与えていないかを迅速に検証できるようになります。
1. ユニットテストの準備:pytestとテストコード
CodeBuildでテストを自動化するには、まずプロジェクトにユニットテストが書かれている必要があります。Python開発で最も人気があり、シンプルで強力なテストフレームワークである pytest を使用します。
プロジェクト構成の確認
これまでのmy-python-appプロジェクトに、以下のファイルが揃っていることを確認してください。
my-python-app/
├── hello.py # テスト対象のアプリケーションコード
├── requirements.txt # プロジェクトの依存関係
├── test_hello.py # ユニットテストコード
└── buildspec.yml # CodeBuildのビルド定義ファイル
requirements.txt と test_hello.py の再確認
4日目の記事で作成したファイルを再掲します。
requirements.txt
pytest==7.1.2
test_hello.py
# test_hello.py
# テスト対象のモジュールをインポート
from hello import greet
# テスト関数は `test_` で始まる名前にする
def test_greet_with_name():
"""名前に応じた挨拶文を返すかテスト"""
assert greet("Alice") == "Hello, Alice!"
def test_greet_with_empty_name():
"""空の名前の場合でも動作するかテスト"""
assert greet("") == "Hello, !"
pytestは、test_ で始まるファイルや関数を自動的にテストとして認識し、実行してくれます。
2. CodeBuildでのユニットテスト自動化
次に、このpytestをCodeBuildのビルドプロセスに組み込みます。CodeBuildは、リポジトリのルートにあるbuildspec.ymlを読み込んでビルドを実行するため、このファイルを編集します。
buildspec.yml の修正
4日目に作成したbuildspec.ymlに、pytestの実行と、テスト結果をレポートとして出力する設定を追加します。
# buildspec.yml
version: 0.2
phases:
install:
runtime-versions:
python: 3.9
commands:
# プロジェクトの依存関係をインストール
- pip install -r requirements.txt
# pytestをインストール
- pip install pytest
build:
commands:
- echo "Running unit tests with pytest..."
# pytest を実行し、JUnit XML形式でレポートを出力
- pytest --junitxml=reports/junit_report.xml
# ビルド成果物(Artifacts)の指定
artifacts:
# テストレポートファイルを成果物として含める
files:
- 'reports/junit_report.xml'
discard-paths: yes
# テストレポートの指定
reports:
pytest_reports:
files:
- 'reports/junit_report.xml'
file-format: JUNITXML
# テスト結果が失敗した場合、ビルドを失敗させる
# ここでは、必ずテストを実行するようにするため、`base-directory`を指定しない
変更点の解説
-
buildフェーズ:pytest --junitxml=reports/junit_report.xml-
pytestを実行し、すべてのテストを走らせます。 -
--junitxmlオプションは、テスト結果をJUnit XML形式のファイルとして出力するためのものです。この形式は、多くのCI/CDツールでサポートされており、テスト結果を視覚的に表示するために不可欠です。
-
-
artifactsセクション:files: - 'reports/junit_report.xml'- CodeBuildの実行後、このファイルがビルドの成果物として保存されます。CodePipelineでは、この成果物を次のステージに引き渡すために必要となります。
-
reportsセクション:- CodeBuildの新しい機能で、テストレポートを直接コンソール上で可視化するために使用します。
-
files: - 'reports/junit_report.xml':レポートファイルへのパスを指定します。 -
file-format: JUNITXML:ファイルの形式を指定します。
このbuildspec.ymlファイルをCodeCommitリポジトリにプッシュすることで、CodeBuildプロジェクトは次に実行された際に、自動的にユニットテストを実行し、結果をレポートとして出力するようになります。
3. CodePipelineからの自動実行とテスト結果の確認
buildspec.ymlを更新し、CodeCommitにプッシュすると、6日目に設定したCodePipelineが自動的にトリガーされ、ビルドステージが開始されます。
CodeBuildコンソールでのテストレポート確認
-
CodeBuildコンソールに移動:
my-python-app-buildプロジェクトのビルド履歴を開きます。 - 最新のビルド実行を選択: 詳細画面を開きます。
-
テストレポートタブ:
Test reportsタブをクリックすると、pytest_reportsという名前のテストレポートが表示されます。 - 結果の確認: テストレポートには、テストの合計数、成功数、失敗数、スキップ数などが一覧で表示されます。個々のテストケースをクリックすると、その実行時間や詳細なログも確認できます。
テストレポートの表示例:
この視覚的なレポートは、大量のテストケースがあっても、どのテストが成功し、どれが失敗したのかを直感的に把握するのに役立ちます。
4. 失敗時の挙動とフィードバック
ユニットテストの自動化で最も重要なのは、テストが失敗した場合の挙動です。
意図的にバグを仕込んでみましょう。hello.pyを以下のように修正し、Hello, CI/CD Engineer!と返すように変更します。
# hello.py
def greet(name):
# バグを意図的に導入
return "Hello, CI/CD Engineer!"
if __name__ == "__main__":
print(greet("CI/CD Engineer"))
この変更をCodeCommitにプッシュすると、CodePipelineが再び自動的に実行されます。
期待される結果
-
CodeBuildのビルド: ビルドステージで実行される
pytestが、test_greet_with_nameテストで失敗を検出します。 -
パイプラインの停止: テストの失敗により、CodeBuildのビルドは
FAILEDステータスとなり、CodePipelineは次のデプロイステージに進まずに停止します。 - 通知: 設定によっては、ビルド失敗の通知がメールやSlackに送られます。
このように、ユニットテストの自動化をCI/CDパイプラインに組み込むことで、バグのあるコードがデプロイされるのを未然に防ぐことができるのです。
まとめ:ユニットテストとCI/CDの強固な連携
本日は、テストピラミッドの土台であるユニットテストを、AWS CodeBuildと連携させて自動化する方法を学びました。
-
pytestを使ってテストコードを記述し、プロジェクトに含めました。 -
buildspec.ymlにpytestの実行コマンドと、JUnit XML形式でのレポート出力設定を追加しました。 - CodeBuildのコンソールで、テスト結果を視覚的なレポートとして確認できることを体験しました。
- テストが失敗した場合、パイプラインが自動的に停止し、本番デプロイを防ぐことを確認しました。
このユニットテストの自動化は、CI/CDパイプラインにおける品質保証の第一歩です。グローバルなAI企業では、高速な開発サイクルの中で品質を維持するために、このような自動テストの仕組みが不可欠です。
次回は、CI/CDパイプラインをさらに強固にするために、より実践的なテスト戦略、特に「統合テストとE2Eテスト」の自動化について掘り下げていきます。お楽しみに!