開発運用アーキテクチャ

テスト設計 ― ピラミッド+Testcontainers+ブランチカバレッジ ― 生成AI時代のアーキテクチャ超入門

テスト設計 ― ピラミッド+Testcontainers+ブランチカバレッジ ― 生成AI時代のアーキテクチャ超入門

本記事について

当サイトを閲覧いただきありがとうございます。 本記事はシリーズ『生成AI時代のアーキテクチャ超入門』の「開発運用アーキテクチャ」カテゴリ第6弾として、テスト設計について解説する記事です。

テストのゴールはカバレッジの数字ではなく「壊れたときに5分で原因が掴めること」です。本記事ではテストピラミッド・カバレッジ目標値・TDD・flaky対策、「カバレッジ何%狙うか」E2Eはどこまで書くか」「CIで何を走らせるか」といった実務判断を扱います。

本記事のテーマについてさらに詳しく知りたい方は『システム設計のセオリーと実践方法がこれ1冊でしっかりわかる教科書』・『いちばんやさしいClaude Codeの教科書』も参考にしてみてください。

この記事の結論

  • テストピラミッド(ユニット多・E2E少)を守る
  • DB検証はTestcontainersで本番同等にする
  • フレークテストは即隔離し、変更行カバレッジを指標にする

この記事を読む前に

本記事は開発・テスト・リリース・監視といった、サービスを作って動かし続ける工程の話が中心です。IT用語にあまり馴染みがない方は、基礎編の「開発から運用までの流れ」を先に読んでおくと格段に分かりやすくなると思います。また、読んでいて分からない用語が出てきたときは用語集で調べながら読み進められます。

そもそもテスト設計とは何か

車の車検を想像してください。ブレーキ・ライト・排気ガス──項目ごとに検査基準があり、合格しないと公道を走れません。検査なしで走ればいつ事故が起きてもおかしくない状態です。

テスト設計とは、ソフトウェアが正しく動いているかを自動で検証する仕組みをどう構築するかを決めることです。何を・どの粒度で・どのタイミングで検査するかを設計し、コードを変更するたびに自動で確認が走る状態を作ります。

もしテスト設計がなければ、コードを1行変えるたびに「他の機能が壊れていないか」を人力で確認することになり、変更のたびに恐怖が伴います。結果、誰もコードに触れたがらなくなります。

なぜテスト設計が必要か

第一に、変更への恐怖をゼロにするためです。自動テストがあれば変更後に数分でフィードバックが返り、安心してリファクタリングできます。第二に、障害発生時に5分で原因を掴むためです。テストが壊れた箇所を見ればどの変更が問題かが即座にわかり、テストがなければ原因特定に数時間〜数日かかります。第三に、AI生成コードの品質担保です。AIが書いたコードを人間が毎回レビューするのは限界があり、テストで機械的に検証するのが現実的な安全網です。

テストは3つの責務で分けて考える

テストは階層名を覚えるよりそれぞれが何を保証する責務かを掴んだ方が判断に効きます。

階層責務(何を保証するか)代表ツール
Unit Test関数・クラスの論理の正しさJest/Vitest/pytest/JUnit
Integration Testモジュール結合・DB/外部APIとの接続Testcontainers/Supertest
E2E Testユーザー操作の画面越しの動線Playwright/Cypress
Contract Testサービス間の API 契約の互換性Pact/Spring Cloud Contract
Performance Test負荷・レイテンシの数値の境界k6/Gatling

契約テストマイクロサービス環境で重要度が上がっていますが、モノリスでは不要です。必要な階層を選ぶ判断も、アーキテクトの仕事になります。

テストピラミッドの比率とアイスクリームコーン

テストピラミッド(Unit → Integration → E2E)

テストピラミッド(Mike Cohnが2009年に提唱)は、テストを「速く・数が多い・下に積む」「遅く・数が少ない・上に積む」で整理したモデルです。Unit 70/Integration 20/E2E 10の比率はあくまで目安で、決済・在庫などロジック中心ならUnit 80まで寄り、管理画面中心のCRUD業務アプリならIntegrationが30〜40に寄ります。何を最も信頼したいかで比率は決まります。

多くの現場で起きているのが、テストピラミッドが逆三角形になっているケース──E2Eが大量にあってUnitが薄いアイスクリームコーン・アンチパターンです。「E2Eの方が安心感がある」「Unit Testは書くのが面倒」という理由で積み上がりますが、E2Eは数十秒〜数分かかり、非同期処理でフレーク(同じコードなのに実行結果が安定しないテスト)しやすく、壊れるたびに誰も直さずskipタグが積まれていきます。気づいたらE2Eが500本あるが半分skip、残り半分も毎日3本は赤いという地獄になります。Unitの薄さをE2Eでは補えません。

テストで何を走らせるか — 段階別の実務

CIで「全テストを毎回走らせる」のは非現実的です。コードが触れるタイミングで段階を切り、各段階で走らせる種別と量を変えるのが実務の答えです。

段階いつ走るか何を走らせるか目標時間
①pre-commitコミット作成時(ローカル)変更ファイルの Lint + 単一テスト5秒以内
②pre-pushpush 直前変更範囲の Unit Test30秒以内
③PR作成・更新時GitHub に push された時全Unit + 型チェック + 変更範囲Integration10分以内
④merge時main にマージされた瞬間全 Integration + スモーク E2E20分以内
⑤ナイトリー夜間バッチ全 E2E + 負荷試験 + Contract Test数時間

PR時に全E2Eを走らせるのは筋が悪い選択です。開発速度が露骨に落ち、誰もテストを増やさなくなる。E2Eはマージ後のスモーク(最小動線)とナイトリーに分け、PR段階ではUnit + Integrationで十分──これが現場で機能している構成です。

カバレッジ目標は何%を狙うか

テスト設計のピラミッドと実務比率

カバレッジ(コードのうちテストが実行した割合)は下限ラインとして使うもので、目標値ではありません。80%を狙うのは良いが、90%を追い始めた瞬間に意味のないテストが量産されるのが現場の常です。

目標現実的かコメント
40%未満危険テストの下地が薄すぎる。リファクタで即死
60〜70%一般的新規プロジェクト・SaaS の典型ライン
80%本命ドメインロジック中心部は80%を超える設計にする
90%以上要注意儀式化・ゲッターセッターのテスト量産が始まる
100%禁じ手達成コストに見合わない。宗教化する

カバレッジはブランチカバレッジ(if文の条件分岐を両方通したか)を基準に据えるのが現代の定石です。ラインカバレッジだけ見るとif文の片方しか通っていないのに90%という偽陽性が出やすい。PR承認では絶対値より「新規コードのカバレッジ」(変更行ベース、codecovの patch)を見るのが無難です。ドメインロジックは80%超、それ以外は60%が現実的な線引きです。

TDDとフレーク対策

TDDは、失敗するテストを書く(Red)→通す最低限の実装(Green)→リファクタの3ステップを回す開発スタイルです。本質は「テストを先に書くこと」ではなく、仕様を最初に言語化してから実装に入るという思考の順序にあります。実装しながら仕様を考えると「動いたからOK」で終わるのが人間の性で、TDDはその罠を避ける装置です。ただし全機能でTDDを回すのは非現実的で、ドメインロジック中心部(決済・在庫計算・料金判定)はTDD、UI配線・CRUDはテスト後書きで十分、というのが現場のバランスです。

フレークテストはテストの信頼性を崩壊させる最大の敵です。3回に1回落ちるテストが10本あるとCIの緑色は確率的にしか出なくなり、誰も赤を信じなくなります。原因の典型は、時刻依存(Date.now() → fakeTimersで固定)、非同期のタイミング依存(→明示的な waitFor で待つ)、テスト間の状態共有(→各テストでDB・キャッシュをクリーン)、外部API呼び出し(→モック化 or Testcontainersで隔離)、乱数依存(→seed固定)です。フレークは即座に隔離・修正・削除のいずれかを選ぶのが鉄則で、「retryで通ったテストは通っていないのと同じ」という扱いが真っ当なチームの運用です。

テスト用DBとモックの境界

結合テストで最も事故るのがDB接続です。モックでDBを置き換えると「SQLは合ってるはずなのに本番で落ちる」が頻発し、SQLiteで代用するとPostgreSQL / MySQLとの方言差でバグが見つからない。現時点の鉄板はTestcontainers──Dockerコンテナで本物のDB・Redis・Kafkaをテスト時に起動し、終わったら破棄するライブラリで、初回起動こそ遅いものの本番との差はほぼゼロです。「DBの方言まで含めて検証する」は、カバレッジ数字を上げるより100倍価値のある投資です。

モックの境界はシンプルな鉄則で整理できます。モックすべき対象は外部SaaS(Stripe・SendGrid)・時刻・乱数・コストの高い計算。モックしてはいけない対象は自プロジェクトのDB・自分たちが書いたコード・同一プロセス内のモジュール。典型的な失敗は「DBアクセスをリポジトリ層でモック」で、SQLのバグが一切検出されないまま本番に流れます。自分のコードはモックしない、外部世界だけモックするが経験則です。

なお、マイクロサービスBFF2チーム以上で運用し始めたらContract Test(Pact等で呼び出し側の期待と呼ばれ側の実装の一致を機械検証)の導入検討ラインです。テストデータはuserFactory({role: 'admin'}) のようなFactoryパターンが鉄板で、「意味のある差分だけを書き、残りはデフォルト」にするとテストが仕様書として読める形になります。

3つのシナリオで考える

個人開発・スタートアップの場合

ドメインロジックのUnit Testと、最重要動線のスモークE2Eを1本だけ、というところから始めれば十分です。カバレッジ目標は設けずに、「壊れたら困る計算」にだけテストを書くのが現実的だと思います。DBを触るテストは最初からTestcontainersにしておくと、後の拡張がかなり楽になりますよ。

個人・スタートアップ ― 1か月で出せる構成が正解 ― 生成AI時代のアーキテクチャ超入門senkohome.com/arch-intro-case-startup/

中小SaaSの場合

ピラミッド比率の維持と変更行カバレッジ、フレークの即隔離という運用を確立する段階です。PR時はUnitと変更範囲のIntegrationを10分以内に収めて、E2Eはマージ後のスモークとナイトリーに分離します。カバレッジについてはドメイン中核80%・その他60%という線引きが妥当でしょう。

中小SaaS ― マネージドに寄せて少人数で回す ― 生成AI時代のアーキテクチャ超入門senkohome.com/arch-intro-case-saas/

大企業の場合

複数チームでマイクロサービスを運用する構成では、PactなどのContract TestでAPI契約の互換性を機械検証して、チーム間の調整コストを削減する価値が出てきます。規制業種の場合はテストの実施記録そのものがエビデンスとして監査対象になりますので、CI実行履歴の保存期間も設計に含めておいてください。

大企業基幹系 ― 新しい技術より組織で成立する設計 ― 生成AI時代のアーキテクチャ超入門senkohome.com/arch-intro-case-enterprise/

AI判断軸 ― テストがAI活用の品質ゲートになる

テストをAIに書かせる場合の注意点

AIにテストコードを生成させると、正常系のテストは高精度で書けます。しかし以下の問題が頻発します。

  • 境界値テストの漏れ(0件・1件・上限値のケースが抜ける)
  • 異常系の網羅不足(ネットワークエラー・タイムアウト・権限不足のケースを書かない)
  • 実装の内部構造に依存したテスト(リファクタリングで壊れるbrittle test)
  • モック過多(本物のDBを使うべき箇所までモックして偽の安心を得る)

AI生成テストは「初稿」として使い、人間がレビューして境界値・異常系を追加する運用が現実的です。テスト仕様を先に人間が書き、実装をAIに任せるTDDスタイルが最も品質が安定します。

テストがAI活用の品質ゲートとして機能する

AIにコード生成を任せる場合、既存のテストスイートが品質の最後の砦になります。AIが書いたコードをpush→CIで全テスト実行→失敗したら差し戻す、という自動フローが成立していれば、AIの生成品質に不安があっても安全に利用できます。

この前提が成立するには、テストスイート自体の信頼性が高い必要があります。フレークテストが多い・カバレッジが低い・モックだらけでIntegrationが薄い状態では、AIが書いた誤ったコードがテストをすり抜ける確率が上がります。

やってはいけないこと

テスト運用で事故る典型を、特に危険な6つに絞ります。どれも数字や安心感を追って本質を失う構造を持ちます。

禁じ手なぜダメか → どうするか
経営指標にカバレッジ%を採用ゲッターセッターにテストが生えるだけ → 本番流出バグ件数と変更行カバレッジで測る
カバレッジ90〜100%を追う意味のないテストが量産され宗教化する → ドメイン中核80%超・他60%で線を引く
E2Eを積み上げて安心する遅い・フレーク・メンテ放棄の三重苦 → ピラミッドの形を守りUnitに投資する
retryで通ったテストをOK扱い本物のバグまで見逃す文化が根付く → フレークは即隔離・修正・削除
自プロジェクトのDBをモックSQLのバグが検出されないまま本番へ → Testcontainersで本物を使う
「テストを書く時間がない」と先送りデバッグ・本番障害・顧客説明で溶ける時間の方が確実に長い → 中核ロジックから書く

筆者メモ — カバレッジKPI化が壊したチーム

ある中規模SaaS企業で「カバレッジ80%をチームKPIに設定」したところ、3か月でゲッターセッターのテストが数千行増え、一方で本質的なドメインロジックのバグは減らなかった──という事例が業界では知られています。数字は簡単に上がるが、品質は変わらない。なぜなら「カバレッジを上げる」ことと「バグを減らす」ことは別物だからです。

その後このチームはKPI「新規バグの本番流出件数」「PR差分のカバレッジ(変更行ベース)」の2軸に切り替え、絶対値のカバレッジ目標は撤廃しました。結果としてテストの質が戻り、同時にゴミテストが大量に削除されたという、示唆的な顛末です。テストの価値はバグを減らした実績でしか測れません。

決めるべきこと — 自分のプロジェクトでの答えは?

以下の項目について、自分のプロジェクトの答えを1〜2文で言語化してみてください。曖昧なまま着手すると、必ず後から「なぜそう決めたんだっけ」が問われます。

  • テストピラミッドの比率目標(Unit / Integration / E2E
  • カバレッジ目標(全体%・ドメイン中核%・ブランチカバレッジ採用有無)
  • PR時CIで走らせる範囲(変更範囲のみ or 全Unit)
  • E2Eの実行タイミング(merge後スモーク + ナイトリー)
  • テストDB戦略(Testcontainers / モック / 共有DB)
  • フレークテストの扱い方(隔離→修正→削除のフロー)
  • Contract Testの導入要否マイクロサービス / BFF化の有無で判断)
  • テストデータの作り方(Factory / Fixture / Builder)

この記事に関連する記事

まとめ

本記事はテスト設計について、テストピラミッド・カバレッジ・TDD・フレーク対策・Testcontainers・モック境界・AI時代のテスト先行まで含めて解説しました。如何だったでしょうか。

テストピラミッドを意識し、Testcontainersで本番同等のDB検証、ブランチカバレッジ+変更行カバレッジを運用指標に、フレークは即隔離する。これが2026年のテスト設計の現実解です。

次回はCI/CD(パイプライン設計・デプロイ自動化)について解説します。

シリーズ目次に戻る → 『生成AI時代のアーキテクチャ超入門』の歩き方

本記事で扱った内容の詳細は JUnit 5 公式ドキュメント も合わせて参考にしてください。

それでは次の記事も閲覧いただけると幸いです。