Advanced (更新: 2026/6/7)

テストはどこから書く?Claude Codeで決めるテスト戦略の優先順位

テストピラミッドで単体・結合・E2Eの比率を決め、価値の高い所から守る。Claude Codeにテストを書かせる順番、落ちるテストの直し方、テストファーストのコツを実例で。

テストはどこから書く?Claude Codeで決めるテスト戦略の優先順位

「テスト、ちゃんと書いといて」とClaude Codeに頼んだら、200個のテストが緑に並びました。カバレッジは85%。数字だけ見たら優等生です。

その週、本番で価格計算がバグりました。割引が二重にかかって、半額で商品が売れていた。テストは全部緑のまま。

何が起きたか。Claude Codeは「テストしやすい所」を200個テストして、「壊れると売上が飛ぶ所」を1個もテストしていなかったんです。getter、setter、定数を返すだけの関数。緑にするのは簡単だけど、誰の役にも立たないテスト。

このとき僕がやっと腹落ちしたのは、テスト戦略の本質は「たくさん書くこと」じゃないということ。何を・どの層でテストするかを先に決めること。それだけです。今日はその決め方を、僕の失敗ごと共有します。

この記事の要点

  • テスト戦略とは「何をどの層でテストするか」の地図。量ではなく配分で決める。
  • テストピラミッドの目安は、単体6〜7割・結合2〜3割・E2E1割弱。下ほど速く、上ほど壊れやすい。
  • 書く価値が高いのは「壊れると売上・信用・データに直結する所」。getter/setterや定数は後回し。
  • Claude Codeには「対象・層・触ってよい範囲・禁止事項」を渡す。落ちるテストは弱めず原因で直させる。
  • 単体の細部はVitestの実践記事、E2Eの細部はPlaywrightの実践記事へ。ここは全体像。

テスト戦略って、結局どこから書くの

新しい機能ができた。テストを書こう。さあどこから——ここで止まる人が多い。僕もそうでした。

考え方はシンプルです。壊れたとき、誰がどれだけ困るかで並べる。価格計算が壊れたら売上に直撃。ログイン認証が壊れたら全ユーザーが入れない。一方、トップページの見出しの色が変わってもお金は減りません。困る順に並べて、上から守る。これだけで「目立つ画面から書いて、肝心な所が抜ける」事故が消えます。

もう一つの軸が「どの層でテストするか」です。同じ機能でも、関数1個の計算なら単体テスト、画面で動くかは結合テスト、購入が最後まで通るかはE2Eテスト。層が下ほど速くて壊れにくく、上ほど遅くて壊れやすい。だから安いものから厚く積む。これを図にしたのがテストピラミッドです。

テストピラミッドで比率を決める

テストピラミッドは、下に速い単体テスト、真ん中に結合テスト、上に少数のE2Eを置く配分の地図です。ピラミッドという名前ですが「絶対この比率」というルールではありません。変更頻度と、壊れたときの原因の見つけやすさで層を分けるための目安です。

flowchart TB
  E2E["E2E 1割弱: 購入・登録・ログインなど主要導線"]
  INT["結合 2〜3割: API・DB・フォーム・コンポーネント"]
  UNIT["単体 6〜7割: 価格計算・権限判定・入力検証"]
  E2E --> INT --> UNIT
レイヤー目安守るもの速度と安定主なツール
単体テスト60-70%計算、分岐、バリデーション、権限判定速い・壊れにくいVitest
結合テスト20-30%Reactコンポーネント、API、DB境界中くらいVitest + Testing Library
E2Eテスト5-10%購入・登録・ログインなど主要導線遅い・壊れやすいPlaywright
CIの品質ゲート全PRlint、型、単体、E2E、レポート保存GitHub Actions

なぜ下を厚くするのか。単体テストは数ミリ秒で終わり、落ちたら「この関数のこの分岐」と一発で原因がわかる。E2Eはブラウザを丸ごと動かすので数秒〜数十秒かかり、落ちても「どこかで失敗した」としか出ない。同じ自信を買うなら、安い層で買ったほうが得なんです。

逆三角形、つまりE2Eばかりのテストは「アイスクリームコーン」と呼ばれて嫌われます。遅い、よく壊れる、原因が見えない。全部E2Eで守ろうとすると、CIが20分かかって誰も回さなくなる。これは僕が実際にやった失敗です。

書く価値が高い所・低い所

ピラミッドの次は中身です。同じ単体テストでも、価値は全然違う。僕が壊して学んだ「優先度」を表にします。

優先度対象の例理由
最優先価格・課金・割引の計算壊れると直接お金が消える
最優先認証・権限・公開範囲の判定壊れると情報漏れ・全停止
入力バリデーション、境界値不正データがDBに入ると後で地獄
削除・上書きなど不可逆な操作やり直せない事故になる
フォーム送信、APIの正常系ユーザー導線の根幹
getter/setter、定数を返す関数壊れにくく、壊れても影響が小さい
見た目・色・余白・文言の細部仕様変更で毎回壊れる割に価値が薄い

ポイントは、カバレッジ80%という数字を目的にしないこと。80%は入り口であって、品質の証明ではありません。残り20%が「支払い・認証・削除」に近いなら、数字を上げる前にそこを最優先で埋める。逆に、その20%が見た目の細部なら、無理に追わなくていい。

価格計算で本当に怖いのは正常系じゃありません。数量0、100%割引、不正な割引率、丸め誤差。Claude Codeに任せると正常系ばかり増やしがちなので、「正常系・境界値・異常系を分けて」と毎回明示します。

Claude Codeにテストを書かせる戦略

ここが本題です。「テスト書いて」だけだと、冒頭の200個地獄になる。僕が落ち着いて指示するために使っているのが、次のテンプレートです。対象ファイル・テスト層・実行コマンド・触ってよい範囲・禁止事項を必ず4点セットで渡す。

src/lib/pricing.ts を読み、Vitestで単体テストを追加してください。

【層】単体テスト(外部I/Oなし)
【観点】正常系・境界値・異常系を3ブロックに分ける
        特に 数量0 / 割引100% / 不正な割引率 / 丸め を厚く
【触ってよい範囲】テストファイルのみ。実装は変更しない
【禁止】snapshotだけで済ませる / skip / カバレッジ稼ぎの空テスト
【最後に】npm run test -- pricing を実行し、結果を要約

実装にバグの疑いがあれば、テストを書く前に箇条書きで報告してください。

「禁止」を渡すのがコツです。「いいテストを書いて」は曖昧すぎて、AIは無難な(=薄い)方に逃げます。「CSSクラスに依存しない」「snapshot単独で済ませない」「skipしない」「CIで再現できるように」と、ダメな例を先に潰すと出力が安定する。これは何十回も依頼して掴んだ実感です。

落ちるテストの直し方

Claude Codeのテストはよく落ちます。問題はその直し方。放っておくと、AIはテストを弱くして緑にしようとする。タイムアウトを伸ばす、expectをゆるめる、.skipをつける。これは「体温計を割って熱を下げる」のと同じで、最悪です。

なので僕は、落ちたときこう指示します。

このテストがCIで落ちます。ログは添付のとおりです。

まず原因を、次のどれかに分類してください:
  モックの後始末漏れ / 偽タイマーの戻し忘れ / 非同期の待ち漏れ /
  テスト間の状態共有 / 実装側の本物のバグ

そのうえで【原因に対する最小修正】を提案してください。
タイムアウトを伸ばすだけ・skip・アサーションを緩める修正は禁止です。
実装側のバグなら、テストではなく実装の修正案を出してください。

「分類してから直せ」と段取りを踏ませると、見当違いの修正がぐっと減ります。モックの巻き上げや偽タイマーといった、Vitestで落ちる定番の原因と直し方はVitestのモックとカバレッジを“落ちない”状態にする記事に詳しくまとめました。E2Eが通ったり落ちたりするフレーキーの潰し方はPlaywrightのフレーキー対策の記事へ。この記事は地図なので、各層の細かい直し方はそちらに送ります。

テストファーストで仕様を固める

もう一つの戦略がテストファースト、いわゆるTDDです。実装の前にテストを書く。Claude Codeと相性がいいのは、テストが「やってほしいことの仕様書」になるから。先に期待する入出力を書いておくと、AIは「緑にする」という明確なゴールに向かって実装します。曖昧な日本語で説明するより、ずっとブレません。

calculateTotal(unitPrice, quantity, discountRate?, taxRate?) を
これから実装します。まず先にVitestのテストだけ書いてください。

期待する仕様:
  - 税率は既定10%、割引は税抜に対してかける
  - 数量は0以上の整数。負数や小数は例外
  - 割引率・税率は0〜1の範囲外なら例外
  - 最終額は四捨五入

テストを書いたら実行し、全部赤いことを確認してから止まってください。
実装はまだ書かないでください。

赤を確認してから実装に進むのが肝です。最初から緑だと「そのテスト、本当に動いてる?」が分からない。TDDの進め方そのものはClaude CodeとTDDの実践記事にまとめてあります。

コピペで動く:価格計算の単体テスト

戦略の話ばかりだと宙に浮くので、最優先ゾーン(価格計算)の実物を置きます。vitest を入れればそのまま走ります。

npm i -D vitest
npx vitest run

実装側。割引を税抜にかけ、最後に四捨五入。境界と異常系を例外で弾きます。

// src/lib/pricing.ts
export type PriceInput = {
  unitPrice: number;
  quantity: number;
  discountRate?: number; // 0〜1
  taxRate?: number;      // 0〜1(既定10%)
};

export function calculateTotal({
  unitPrice,
  quantity,
  discountRate = 0,
  taxRate = 0.1,
}: PriceInput): number {
  // 異常系は最初に弾く。後でDBに不正値が入る事故を防ぐ
  if (!Number.isInteger(quantity) || quantity < 0) {
    throw new Error("quantity must be a non-negative integer");
  }
  if (unitPrice < 0) throw new Error("unitPrice must be non-negative");
  if (discountRate < 0 || discountRate > 1) {
    throw new Error("discountRate must be between 0 and 1");
  }
  if (taxRate < 0 || taxRate > 1) {
    throw new Error("taxRate must be between 0 and 1");
  }

  const subtotal = unitPrice * quantity;
  const discounted = subtotal * (1 - discountRate); // 割引は税抜にかける
  return Math.round(discounted * (1 + taxRate));     // 最後に四捨五入
}

テスト側。正常系・境界値・異常系を3ブロックに分けるのがミソ。緑の数ではなく、怖い所を狙い撃ちします。

// src/lib/pricing.test.ts
import { describe, expect, it } from "vitest";
import { calculateTotal } from "./pricing";

describe("calculateTotal", () => {
  // 正常系:まず普通のケース
  it("税込合計を計算する", () => {
    expect(calculateTotal({ unitPrice: 1000, quantity: 2 })).toBe(2200);
  });
  it("割引を税の前にかける", () => {
    expect(
      calculateTotal({ unitPrice: 1000, quantity: 2, discountRate: 0.2 })
    ).toBe(1760);
  });

  // 境界値:0や100%割引など、バグが潜む端っこ
  it("数量0は0円", () => {
    expect(calculateTotal({ unitPrice: 1000, quantity: 0 })).toBe(0);
  });
  it("100%割引は0円", () => {
    expect(
      calculateTotal({ unitPrice: 1000, quantity: 3, discountRate: 1 })
    ).toBe(0);
  });

  // 異常系:不正な入力はちゃんと例外を投げる
  it("不正な数量と割引率は例外", () => {
    expect(() => calculateTotal({ unitPrice: 1000, quantity: -1 })).toThrow();
    expect(() =>
      calculateTotal({ unitPrice: 1000, quantity: 1, discountRate: 1.2 })
    ).toThrow("discountRate must be between 0 and 1");
  });
});

このテストが緑なら、冒頭の「割引二重がけで半額」は二度と起きません。たった数十行ですが、200個の薄いテストより、この5個のほうがずっと仕事をします。

CIで「弱いテスト」を止める

ローカルで緑でも、公開前の品質は守れません。PRごとに lint・型・単体・E2E を回し、落ちたらマージできない壁を作る。これがあると、AIがこっそり混ぜた .skip や脆いテストも、人間のレビュー前に炙り出せます。

# .github/workflows/test.yml
name: Test
on:
  pull_request:
  push:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v6
        with:
          node-version: 22
          cache: npm
      - run: npm ci
      - run: npm run test:coverage
      - name: Install Playwright browsers
        run: npx playwright install --with-deps
      - run: npm run test:e2e
        env:
          CI: "true"
      - uses: actions/upload-artifact@v5
        if: ${{ !cancelled() }}
        with:
          name: playwright-report
          path: playwright-report/
          retention-days: 30

Claude Code GitHub Actionsを併用するなら、公式ドキュメントではGA版の anthropics/claude-code-action@v1 が案内されています。古い @beta 前提の記事を真似しないこと。CIの組み方全体はClaude CodeでCI/CDパイプラインを構築する記事にまとめています。なお公式の一次情報は、Claude CodeのCommon workflowsVitestのCoverageガイドPlaywrightのCIガイドで確認できます。

よくある質問

Q. テストはどこから書き始めればいい? A. 「壊れたとき一番困る所」からです。価格計算・課金・認証・権限・削除のような、売上や信用やデータに直結する所を単体テストで固めるのが先。トップページの見た目は後回しで構いません。

Q. カバレッジは何%を目指せばいい? A. 80%を一応の入り口にしつつ、数字そのものを目的にしないこと。残りの未テスト分岐が支払いや認証に近いなら、80%でも足りません。逆に見た目の細部なら、無理に100%を狙わなくていい。中身が大事です。

Q. Claude Codeが書いたテストが落ちます。どう直す? A. まず「原因を分類してから直せ」と指示します。タイムアウトを伸ばす・skip・アサーションを緩める、は禁止と明示する。原因が実装側のバグなら、テストではなく実装を直させます。詳細はVitestの記事へ。

Q. E2Eは何本くらい書けばいい? A. 全体の1割弱、本数で言えば主要導線に数本で十分です。購入・登録・ログインのような「壊れると致命的な導線」だけ。画面の見た目をE2Eで固定すると、改善のたびに壊れて消耗します。

Q. テストファースト(TDD)は本当に効く? A. Claude Codeとは特に相性がいいです。先に書いたテストが「仕様書」になり、AIが緑というゴールに向かって実装するから。曖昧な日本語の指示より、期待する入出力を先に固めるほうがブレません。

実際に試した結果

ClaudeCodeLabの収益導線で試して、一番効いたのは「E2Eを増やす」ことではありませんでした。単体テストで価格計算を固定し、Testing LibraryでCTAの役割と文言を守り、Playwrightは記事から商品ページへ進める1本に絞る。これだけで、薄いテストを200個積んでいた頃より安心して公開できるようになりました。

Claude Codeへの依頼は、最初に禁止事項(CSS依存・snapshot単独・skip・タイムアウト水増し)を並べ、最後に npm run test:coverage の結果を要約させる。たったこれだけで、脆いテストが目に見えて減ります。

残った課題は、外部決済や広告タグのようにローカルで完全再現しにくい部分。ここはCIのレポートと手動確認の合わせ技でしのいでいます。テストは「全部自動で完璧」を狙うより、壊れると困る順に、安い層から守る。それが、遠回りに見えていちばん速い道でした。

各層の深掘りはVitestの実践記事Playwrightの実践記事へ。不具合調査にテストを使う流れはClaude Codeデバッグテクニックが、繰り返し使うレビュー観点のまとめは教材一覧が役に立ちます。

#Claude Code #テスト戦略 #テストピラミッド #Vitest #Playwright
無料

無料PDF: Claude Code はじめてのチートシート

まずは無料PDFで基本コマンドと最初の使い方をまとめて確認してください。登録後はそのままテンプレート集や導入相談にも進めます。

スパムは送りません。登録情報は厳重に管理します。

Claude Codeを仕事で使える形にしませんか?

まず無料PDFで基本を固め、繰り返し使う作業はGumroad教材へ、チーム導入や権限設計は導入相談へ進めます。

Masa

この記事を書いた人

Masa

Claude Codeの実務活用、導入設計、収益導線改善を検証しているエンジニア。10言語の技術メディアを運営中。

PR

関連書籍・参考図書

この記事のテーマに関連する書籍を楽天ブックスで探せます。

※ 当サイトは楽天市場のアフィリエイトプログラムに参加しています。上記リンクから商品をご購入いただくと、運営者に紹介料が支払われる場合があります。