この記事は、CYBOZU SUMMER BLOG FES '25 の記事です。
目次
はじめに
こんにちは。サイボウズでエンジニアリングマネージャーをしているhigaです。
近年、複数のプロダクトを複数のチームが並行して開発する組織が増えています。このような開発体制では、各プロダクトが正常に動作することを確認するE2E(End-to-End)テストがとても重要になってきます。
この記事では、私たちが開発・運用しているグローバル向けAWS版kintoneにおけるE2Eテストの仕組みについて紹介します。複数プロダクトの開発が進む中で、どのように安定したテスト環境を提供しているか、その仕組みについて詳しく解説します。
なぜE2Eテストが重要なのか
複数のチームが異なるプロダクトを分担開発する環境では、以下のような品質リスクが存在します。
- プロダクト間連携:異なるプロダクト間連携の不具合
- 共通基盤影響:基盤変更が各プロダクトに与える予期しない影響
- 統合テストの困難さ:チーム間の開発サイクルの違いによる課題
これらの問題を解決するには、本番環境に近い環境で実際のユーザーフローを再現するE2Eテストが重要です。
本記事で紹介するアプローチ
この記事では、以下の点に焦点を当てて、私たちの取り組みを紹介します。
- 責任分界点の明確化:プロダクトチームとプラットフォームチームの役割分担
- チーム独立性の確保:各プロダクトチームが自由にテストを追加・修正できる仕組み
- E2Eテスト基盤の汎用性:Kubernetes Jobによる汎用的なテスト実行環境
各プロダクトチームが独立してE2Eテストケースを作成・修正しながら、プラットフォームチームがE2Eテスト基盤を運用する仕組みについて、実際に私たちのチームで運用している基盤を例に解説していきます。
責任分界点を明確にしたアーキテクチャ設計
プロダクトチーム分散開発でE2Eテストを成功させるには、「誰が何に責任を持つか」を明確にすることが重要です。ここでは、私たちが設計したアーキテクチャについて説明します。
Kubernetes JobによるE2Eテスト実行基盤
先ほど説明したように、グローバル向けAWS版kintoneにおけるE2Eテストの実態はKubernetes Jobです。Kubernetes JobによってE2Eテストが実行されることでプラットフォームチームとしては以下のメリットがあります。
- 完全な環境分離:各テストが独立したコンテナで実行され、テスト間の影響を排除できる
- スケーラビリティ:複数のテストを並行実行でき、リソースを効率的に活用できる
- 標準化された実行モデル:どんなテストでも同じ方式で実行・管理することができる
また、プロダクトチームにとっても以下のようなメリットがあります。
- 完全な独立性:各テストが独立したコンテナで実行されるため、他のチームの影響を受けずに自由にテストケースの追加・修正が可能
- 技術スタック選択の自由:どのプログラミング言語やテストフレームワークでも使用可能
- 開発サイクルの独立性:自分たちのペースでコンテナイメージをビルド・デプロイでき、他チームの都合に合わせる必要がない
これらを踏まえ、以下のような責任領域を設計することで、各プロダクトチームとプラットフォームチームでの協業が可能になっています。
プロダクトチーム責任領域
- テストケースの作成・修正
- コンテナイメージの作成と管理
- テスト結果の解釈
プラットフォームチーム責任領域
- テスト実行基盤の提供と管理
- テスト用リソースの管理
- テスト実行の状態管理
全体アーキテクチャ
各コンポーネントの役割は以下の通りです。
- Test Management Service
- プロダクトチームからのテスト実行要求を受け取り、テスト全体のライフサイクルを管理するAPIサービス
- Job Queue
- テスト実行要求を順序立てて処理し、複数のテスト要求を効率的に管理するキューシステム
- DynamoDB
- テストの実行状態やメタデータを保存し、テストIDごとの進行状況を追跡するNoSQLデータベース
- EKS Cluster
- 実際のE2Eテストが実行され、各テストを独立したJobとして動作させるKubernetes環境
- S3
- テスト実行結果やログファイルを保存し、テスト完了後の結果参照に使用されるオブジェクトストレージ
テスト実行フローの詳細
プロダクトチームがAPIを呼び出してから、実際にテストが完了するまでの流れを説明します。
1. プロダクトチームがAPIでE2Eテストの実行を要求(API)
# CI/CDパイプラインからの実行例 curl -X POST https://test-management-service.kintone.com/v1/ui-test/execution \ -d '{ "product": "kintone", "concurrency": 10, "version": "v1.2.3" }'
(上記エンドポイントやパラメータはイメージで、実際のものとは異なっています)
2. Test Management ServiceがAPIを処理し、テストのための準備を実行する
APIでテスト実行を受け付けたTest Management Serviceが、テスト実行の準備としてメタデータ永続化や各種リソースの用意を行います。
- 一意なテストIDを作成し、テストメタデータをDynamoDBに保存
- テストに必要な各種リソース(コンテナ、DBリソースなど)をテスト環境にデプロイ
3. Kubernetes Jobの生成と実行
Test Management Serviceではテスト用のテンプレートファイルを持っており、実際のテスト実行に合わせてテンプレート展開を行います。
# テンプレート例 apiVersion: batch/v1 kind: Job metadata: name: {{ product }}-test-runner-{{ parameter "TestId" }} labels: testId: "{{ parameter "TestId" }}" spec: template: spec: containers: - name: junit image: {{ parameter "ContainerImage" }} env: - name: TEST_ID value: "{{ parameter "TestId" }}" - name: TEST_RETRY value: "3" resources: requests: memory: 2048Mi cpu: 1000m limits: memory: 2048Mi cpu: 2000m
(上記ファイルは例示のためのものであり、実際のファイルとは異なっています)
このテンプレート展開により、動的なパラメータと静的なパラメータを同時に管理することが可能となっています。
動的なパラメータの例
- TestId:テスト実行ごとに生成される一意のID
- version:プロダクトチームが指定するプロダクトバージョン
静的なパラメータの例
- TEST_RETRY:プロダクトやテスト種類ごとに事前に決められたリトライ回数
- Memory/CPU Limits:テスト用コンテナごとのリソース設定
例えば、UIテストでは並行実行数が多いためメモリを多く割り当て、APIテストでは軽量な設定にする、といった使い分けを行っています。また、特定のプロダクトでは過去の実績からリトライ回数を多めに設定するなど、プロダクトの特性に応じた最適化も可能です。
テストIDをコンテナに埋め込むことによって、実際のKubernetes上でのトレースなども行いやすいよう留意しています。
ここでは、以下のような処理を行っています。
- テンプレート展開により、テスト用のKubernetes Jobマニフェストを作成
- Kubernetes APIでJobを作成
- コンテナ内でテスト実行
4. テスト完了と後処理
テスト完了後の後処理を行います。
処理の中で特に大事なのがテスト用リソースの削除処理です。複数のプロダクトチームが頻繁にテストを実行する環境では、テスト用リソース削除機能がないとすぐにリソースが枯渇してしまいます。
- テスト成功/失敗の判定
- テスト結果をS3にアップロード
- テスト用リソースの削除
まとめ
本記事では、プロダクトチーム分散開発におけるE2Eテストシステムについて、実際に運用しているE2Eテスト基盤を紹介しました。
重要なポイント
- 責任分界点の明確化:プロダクトチームはテスト内容、プラットフォームチームは実行基盤に集中することで、各チームが専門領域に注力できます。
- Kubernetes Jobの活用:コンテナベースの実行により、環境分離と技術選択の自由を実現しながら、統一された運用が可能になります。
- テンプレート展開:動的・静的パラメータの組み合わせで、プロダクト特性に応じた最適化と運用の標準化を両立しています。
他の組織への示唆
このアプローチは、複数プロダクトを並行開発し、チーム間で技術スタックが異なる組織に特に有効だと思います。重要なのは技術的な仕組みだけでなく、組織としての責任分界点を明確にすることです。
プロダクトチーム分散開発におけるE2Eテストは継続的な改善が重要であり、今回紹介したアプローチが同様の課題を抱える組織の参考になれば幸いです。