ANTIGRAVITY LABEN
記事一覧/Tips & 活用術
Tips & 活用術/2026-04-01上級

Antigravity × TDD実践マスター:AIとペアでバグゼロを実現する開発戦略

AntigravityとTDD(テスト駆動開発)を組み合わせた実践的な開発戦略を解説。Jest・Vitest・Playwright・Detoxを使った自動テスト生成からCI/CDまで、バグゼロを目指すプロ向け完全ガイド。

TDD2テスト自動化Jest2Playwright2CI/CD17品質保証6ペアプログラミング

取り組みの背景:なぜAntigravity × TDDなのか

「AIに書いてもらったコードは動くが、リグレッションが怖い」——そう感じたことはないでしょうか。Antigravityをはじめとするコーディングアシスタントは、驚くほどの速度でコードを生成してくれます。しかし、テスト無しで高速に積み上げたコードベースは、やがて変更のたびに壊れる「砂の城」になりかねません。

テスト駆動開発(TDD)は、この問題に対するもっとも根本的な解答です。そしてAntigravityは、TDDの最大の障壁だった「テストを書く手間」を劇的に下げてくれます。両者を組み合わせると、「高速×安全」という一見矛盾する二つの目標を同時に達成できます。

ここではAntigravityとともに本物のTDDを実践するための、ゼロからプロダクション品質までの完全ワークフローをお伝えします。環境セットアップから始まり、ユニット・統合・E2Eテストの設計パターン、そしてCI/CDへの統合まで、実際に手を動かせる内容でまとめましました。

対象読者

この記事は以下に当てはまる方に最適です。

  • Antigravityをすでに使っているが、テスト戦略が曖昧なまま開発を進めている
  • TDDに興味はあるが、AIとどう組み合わせればよいかわからない
  • テストを書いているが、カバレッジが低く本番障害が続いている
  • ソロまたは小チームで品質と開発速度を両立したい

第1章:TDDとAntigravityの相性が抜群な理由

従来のTDDの課題

TDDの理念——「先にテストを書き、そのテストを通すコードを書く」——は美しいものの、実践では多くの開発者がつまずきます。その主な理由として、テストコードそのものを書く時間的コスト、テストのセットアップ(モック、フィクスチャ)の複雑さ、テスト設計のスキル不足が挙げられます。

AntigravityがTDDを変える

Antigravityは以下の点でTDDのボトルネックを解消します。

1. テストコード自動生成

対象となるビジネスロジックの仕様を自然言語で説明するだけで、Antigravityはテストケースを提案してくれます。エッジケースや境界値のテストも漏れなく生成できます。

2. モック・スタブの自動構築

依存関係の複雑なモジュールのモック作成は、初学者の大きな壁です。Antigravityはコードの依存グラフを解析し、適切なモック構造を提案します。

3. リファクタリング時の安全網

既存コードをAntigravityでリファクタリングする際、テストスイートがあれば「壊してしまった」瞬間にすぐ検知できます。AntigravityのAgent機能はテスト失敗を検知して自動的に修正を試みます。

TDDサイクルのAntigravity統合フロー

従来のRed→Green→Refactorサイクルに、Antigravityを組み込むと次のようになります。

1. [Red]  仕様をAntigravityに説明 → テストコードを生成 → テスト失敗を確認
2. [Green] Antigravityに「このテストを通す最小限の実装を書いて」と依頼
3. [Refactor] Antigravityに「SOLID原則に従ってリファクタして」と依頼 → テスト再実行

このサイクルを回すことで、「テストに守られた高品質なコード」が自然と積み上がっていきます。


第2章:環境セットアップ — テスト基盤の構築

必要なツールスタック

Next.js / React プロジェクトを前提に、以下の構成を推奨します。

# ユニット・統合テスト
npm install -D vitest @vitest/ui jsdom @testing-library/react @testing-library/user-event
 
# APIルートのテスト
npm install -D supertest @types/supertest
 
# E2Eテスト
npm install -D @playwright/test
npx playwright install
 
# カバレッジレポート
npm install -D @vitest/coverage-v8

vitest.config.ts の設定

import { defineConfig } from 'vitest/config'
import react from '@vitejs/plugin-react'
import path from 'path'
 
export default defineConfig({
  plugins: [react()],
  test: {
    environment: 'jsdom',
    globals: true,
    setupFiles: ['./src/test/setup.ts'],
    coverage: {
      provider: 'v8',
      reporter: ['text', 'json', 'html'],
      // カバレッジ閾値(80%未満でCIを失敗させる)
      thresholds: {
        lines: 80,
        functions: 80,
        branches: 75,
        statements: 80,
      },
    },
  },
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
    },
  },
})

Antigravityへの最初の依頼

環境を整えたら、Antigravityに以下のように依頼してみましょう。

このプロジェクトのテスト環境(vitest + React Testing Library)が整いました。
src/lib/pricing.ts の getPriceInJPY 関数のユニットテストを
TDDスタイルで作成してください。
エッジケース(0円、負の値、小数点)も含めてください。

Antigravityは関数の実装を読み込み、包括的なテストスイートを生成します。


第3章:ユニットテスト — ビジネスロジックの堅牢化

Antigravityを使ったテスト生成の実例

例として、記事のフィルタリングロジックをテストする場面を見てみましょう。

まずAntigravityに依頼します:「src/lib/articles.tsfilterArticlesByCategory 関数に対するVitest テストを書いてください。カテゴリ一致・不一致・空配列・undefinedカテゴリのケースを含めてください。」

生成されるテストは以下のようになります。

// src/lib/articles.test.ts
import { describe, it, expect } from 'vitest'
import { filterArticlesByCategory } from './articles'
import type { ArticleMeta } from '@/types'
 
const mockArticles: ArticleMeta[] = [
  { slug: 'intro-a2a', category: 'agents', premium: false, title: 'A2A入門', date: '2026-04-01' },
  { slug: 'custom-mcp', category: 'integrations', premium: true, title: 'MCPサーバー構築', date: '2026-04-01' },
  { slug: 'tdd-guide', category: 'tips', premium: true, title: 'TDD実践', date: '2026-04-01' },
]
 
describe('filterArticlesByCategory', () => {
  it('指定カテゴリの記事のみ返す', () => {
    const result = filterArticlesByCategory(mockArticles, 'agents')
    expect(result).toHaveLength(1)
    expect(result[0].slug).toBe('intro-a2a')
  })
 
  it('存在しないカテゴリは空配列を返す', () => {
    const result = filterArticlesByCategory(mockArticles, 'nonexistent')
    expect(result).toHaveLength(0)
  })
 
  it('空配列を渡すと空配列を返す', () => {
    const result = filterArticlesByCategory([], 'agents')
    expect(result).toHaveLength(0)
  })
 
  it('undefinedカテゴリは全記事を返す', () => {
    const result = filterArticlesByCategory(mockArticles, undefined)
    expect(result).toHaveLength(mockArticles.length)
  })
})

このテストがすべてパスしたら、実装は正しく動いていると確信できます。

モックの自動生成テクニック

外部依存(APIコール・DBアクセス)があるモジュールのテストでは、Antigravityにこう依頼します:「src/lib/stripe.ts のStripe APIをモック化して、createCheckoutSession のユニットテストを書いてください。成功・失敗・タイムアウトのケースを含めてください。」

// src/lib/stripe.test.ts
import { describe, it, expect, vi, beforeEach } from 'vitest'
import { createCheckoutSession } from './stripe'
 
// Stripeモジュール全体をモック
vi.mock('stripe', () => ({
  default: vi.fn().mockImplementation(() => ({
    checkout: {
      sessions: {
        create: vi.fn(),
      },
    },
  })),
}))
 
import Stripe from 'stripe'
 
describe('createCheckoutSession', () => {
  let mockCreate: ReturnType<typeof vi.fn>
 
  beforeEach(() => {
    const stripeInstance = new (Stripe as any)('test_key')
    mockCreate = stripeInstance.checkout.sessions.create
  })
 
  it('正常系: セッションIDを返す', async () => {
    mockCreate.mockResolvedValueOnce({ id: 'cs_test_123', url: 'https://checkout.stripe.com/...' })
 
    const result = await createCheckoutSession({ priceId: 'price_test', locale: 'ja' })
 
    expect(result.id).toBe('cs_test_123')
    expect(mockCreate).toHaveBeenCalledWith(
      expect.objectContaining({ mode: 'payment' })
    )
  })
 
  it('異常系: Stripeエラーを適切に伝播する', async () => {
    mockCreate.mockRejectedValueOnce(new Error('Invalid API Key'))
 
    await expect(createCheckoutSession({ priceId: 'price_test', locale: 'ja' }))
      .rejects.toThrow('Invalid API Key')
  })
})

第4章:統合テスト — コンポーネントとAPIの検証

React Testing Libraryによるコンポーネントテスト

UIコンポーネントのテストでは、実装の詳細ではなくユーザーの操作と結果に着目する点が肝心です。Antigravityを使うと、このアプローチを自然と習慣化できます。

依頼例:「MembershipCTA コンポーネントのテストを書いてください。会員・非会員それぞれの表示確認と、ボタンクリック時の動作(/api/checkout へのPOST)のテストを含めてください。」

// src/components/MembershipCTA.test.tsx
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
import { vi } from 'vitest'
import MembershipCTA from './MembershipCTA'
 
// fetch のモック
global.fetch = vi.fn()
 
describe('MembershipCTA', () => {
  beforeEach(() => {
    vi.clearAllMocks()
  })
 
  describe('非会員ユーザー', () => {
    it('「プレミアム会員になる」ボタンが表示される', () => {
      render(<MembershipCTA isPremium={false} />)
      expect(screen.getByRole('button', { name: /プレミアム/i })).toBeInTheDocument()
    })
 
    it('ボタンクリックで /api/checkout に POST される', async () => {
      const mockFetch = vi.mocked(fetch)
      mockFetch.mockResolvedValueOnce({
        ok: true,
        json: async () => ({ url: 'https://checkout.stripe.com/session_test' }),
      } as Response)
 
      render(<MembershipCTA isPremium={false} />)
      fireEvent.click(screen.getByRole('button', { name: /プレミアム/i }))
 
      await waitFor(() => {
        expect(mockFetch).toHaveBeenCalledWith('/api/checkout', expect.objectContaining({
          method: 'POST',
        }))
      })
    })
  })
 
  describe('会員ユーザー', () => {
    it('メンバーシップ案内ではなく感謝メッセージが表示される', () => {
      render(<MembershipCTA isPremium={true} />)
      expect(screen.getByText(/ありがとうございます/i)).toBeInTheDocument()
      expect(screen.queryByRole('button', { name: /プレミアム/i })).not.toBeInTheDocument()
    })
  })
})

APIルートのテスト(Supertest + Vitest)

Next.js App RouterのAPIルートを直接テストするには、Supertestが便利です。

// src/app/api/checkout/route.test.ts
import { describe, it, expect, vi } from 'vitest'
import { POST } from './route'
import { NextRequest } from 'next/server'
 
vi.mock('@/lib/stripe', () => ({
  createCheckoutSession: vi.fn().mockResolvedValue({
    url: 'https://checkout.stripe.com/test',
  }),
}))
 
describe('POST /api/checkout', () => {
  it('正常: セッションURLを返す', async () => {
    const request = new NextRequest('http://localhost:3000/api/checkout', {
      method: 'POST',
      body: JSON.stringify({ priceId: 'price_test_premium', planType: 'premium' }),
      headers: { 'Content-Type': 'application/json' },
    })
 
    const response = await POST(request)
    const data = await response.json()
 
    expect(response.status).toBe(200)
    expect(data.url).toContain('checkout.stripe.com')
  })
 
  it('異常: priceId未指定は400エラー', async () => {
    const request = new NextRequest('http://localhost:3000/api/checkout', {
      method: 'POST',
      body: JSON.stringify({}),
      headers: { 'Content-Type': 'application/json' },
    })
 
    const response = await POST(request)
    expect(response.status).toBe(400)
  })
})

第5章:E2Eテスト — 実際のユーザー体験を守る

Playwrightによる重要フローの自動化

E2EテストはUIが絡む重要なユーザーフローに絞って書くのがポイントです。すべての画面に書くとメンテナンスコストが跳ね上がるため、Antigravityには「最も重要なフローを3つ挙げてください」と相談してから始めましょう。

典型的な重要フローとして、記事閲覧フロー(一覧→詳細)、プレミアム記事のペイウォール表示フロー、言語切替フロー(日英)が挙げられます。

// e2e/article-flow.spec.ts
import { test, expect } from '@playwright/test'
 
test.describe('記事閲覧フロー', () => {
  test('一覧から詳細ページへ遷移できる', async ({ page }) => {
    await page.goto('/')
 
    // 最初の記事カードをクリック
    const firstArticle = page.locator('[data-testid="article-card"]').first()
    const articleTitle = await firstArticle.locator('h2').textContent()
    await firstArticle.click()
 
    // 詳細ページのタイトルが一致するか確認
    await expect(page.locator('h1')).toContainText(articleTitle!)
    await expect(page).toHaveURL(/\/articles\//)
  })
 
  test('プレミアム記事はペイウォールが表示される(非会員)', async ({ page }) => {
    // クッキーなし(非会員状態)でプレミアム記事にアクセス
    await page.goto('/articles/tips/antigravity-tdd-test-driven-development-mastery')
 
    // ペイウォールの表示を確認
    await expect(page.locator('[data-testid="paywall"]')).toBeVisible()
    await expect(page.locator('[data-testid="paywall"]')).toContainText('プレミアム')
  })
 
  test('英語版に切り替えると英語コンテンツが表示される', async ({ page }) => {
    await page.goto('/articles/tips/antigravity-ai-pair-programming-workflow-guide')
 
    // 言語切替ボタンをクリック
    await page.click('[data-testid="lang-switch-en"]')
 
    await expect(page).toHaveURL(/\/en\/articles\//)
    // HTMLのlang属性確認
    await expect(page.locator('html')).toHaveAttribute('lang', 'en')
  })
})

Antigravityを使ったPlaywrightテスト生成

Antigravityに既存ページのHTMLを見せながら「このページの重要なインタラクションをテストするPlaywrightコードを書いてください」と依頼すると、data-testid の追加提案も含めて適切なテストを生成してくれます。


第6章:カバレッジ戦略 — 何を・どこまでテストすべきか

カバレッジ閾値の設定指針

「カバレッジ100%を目指すべきか」——これはよくある議論です。答えはNOです。Antigravityと一緒に開発する場合、以下の指針が現実的です。

  • ビジネスロジック(src/lib/: 90%以上を目標
  • APIルート(src/app/api/: 85%以上を目標
  • UIコンポーネント(src/components/: 70%以上を目標(純粋な表示ロジックに集中)
  • ページコンポーネント(src/app/: E2Eテストで補完

Antigravityへの依頼:「カバレッジレポートの結果を添付します。カバレッジが低い箇所のテストを優先的に書いてください。ただし、単純なgetterや定数ファイルは除外してください。」

カバレッジレポートの確認コマンド

# カバレッジ付きでテスト実行
npm run test:coverage
 
# HTMLレポートをブラウザで確認(coverage/index.html)
npx vite preview --outDir coverage --base /
 
# 期待する出力例:
# ✓ src/lib/articles.test.ts (12 tests) 234ms
# ✓ src/lib/pricing.test.ts (8 tests) 123ms
# ✓ src/components/MembershipCTA.test.tsx (6 tests) 89ms
# Coverage: Lines 84.2% | Functions 87.5% | Branches 76.3%

第7章:CI/CDパイプラインへの統合

GitHub Actionsでの自動テスト実行

プッシュのたびに全テストを実行し、失敗したらマージをブロックする設定を作りましょう。Antigravityに「このプロジェクト用のGitHub Actions CI設定を作ってください。vitest + playwright を実行し、カバレッジレポートをアーティファクトとして保存してください」と依頼します。

# .github/workflows/ci.yml
name: CI — Test & Quality Gate
 
on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]
 
jobs:
  unit-integration:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
 
      - name: Install dependencies
        run: npm ci
 
      - name: Run unit & integration tests
        run: npm run test:coverage
 
      - name: Upload coverage report
        uses: actions/upload-artifact@v4
        if: always()
        with:
          name: coverage-report
          path: coverage/
 
      - name: Coverage threshold check
        run: |
          LINES=$(cat coverage/coverage-summary.json | jq '.total.lines.pct')
          echo "Line coverage: ${LINES}%"
          if (( $(echo "$LINES < 80" | bc -l) )); then
            echo "❌ Coverage below threshold (80%)"
            exit 1
          fi
          echo "✅ Coverage OK"
 
  e2e:
    runs-on: ubuntu-latest
    needs: unit-integration
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
 
      - name: Install dependencies
        run: npm ci && npx playwright install --with-deps
 
      - name: Build application
        run: npm run build
 
      - name: Run E2E tests
        run: npx playwright test
        env:
          BASE_URL: http://localhost:3000
 
      - name: Upload Playwright report
        uses: actions/upload-artifact@v4
        if: failure()
        with:
          name: playwright-report
          path: playwright-report/

既存のAntigravity × GitHub Actions連携については、AntigravityとGitHub Actionsによる高度なCI/CDパイプライン構築も参考にしてください。


第8章:Antigravityを使ったテストのリファクタリング

テストコードも「作品」として磨く

テストコードが増えると、今度は「テストのメンテナンス」が課題になります。Antigravityはここでも力を発揮します。

重複排除の依頼例:「このテストファイルに重複しているセットアップコードをbeforeEach/afterEachにまとめてください。」

命名改善の依頼例:「テスト名が曖昧です。it('works correctly') のような名前を、失敗時に何が問題かわかるように改善してください。」

テストの独立性チェック:「このテストスイートに順序依存(テストAが失敗するとテストBも落ちる)はありますか?修正案を提示してください。」

テスト品質を高めるAntigravityプロンプト集

# テスト網羅性レビュー
以下の関数 [関数名] のテストを確認してください。
見落としているエッジケースや異常系があれば指摘してください。

# フレイキーテストの修正
このE2Eテストが断続的に失敗します。タイミング問題を修正してください。
エラー: [エラーメッセージ]

# パフォーマンステスト
この関数は100万件のデータを処理します。
100ms以内に完了するかVitest benchmarkで測定するコードを書いてください。

VRTとの組み合わせについては、AntigravityによるVRT(ビジュアルリグレッションテスト)自動化で詳しく解説しています。


まとめ

AntigravityとTDDを組み合わせることで、「高速開発」と「品質保証」を両立する道が開けます。本記事のポイントをまとめると、以下の通りです。

まず、Antigravityはテストコードの生成・モック作成・エッジケースの列挙を自動化し、TDDの最大の障壁を取り除いてくれます。次に、ユニット→統合→E2Eという層構造でテストを設計し、各層でAntigravityを活用することで網羅性と保守性の両立が図れます。そして、GitHub Actions等のCI/CDと連携したカバレッジゲートを設けることで、品質の退化を自動的に検知できます。

テストは「書かされるもの」ではなく、「安心してコードを変える自由を与えてくれるもの」です。Antigravityがその負担を大きく引き受けてくれる今、TDDを実践しない理由はありません。

TDDの思想的背景から実践パターンまでを網羅した、この分野の必読書です。

シェア

お読みいただきありがとうございます

Antigravity Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

Editor View2026-03-14
Antigravity AI でテストコードを自動生成 — 単体・統合・E2E テスト完全戦略
Tips & 活用術2026-03-25
Antigravity の機能を収益に結びつける 3 軸の設計 — 開発速度・量産体制・継続デプロイ
AIエージェント・MCP・マルチエージェント・Manager Surface を、そのまま収益の導線に組み替える設計を扱います。開発速度の変換・プロダクト量産体制・継続的デプロイ収益化という3軸で、個人開発者のロードマップを組み立てます。
Tips & 活用術2026-07-11
新しいマシンで Antigravity が別人になった — 移行で持ち越せるもの・作り直すもの・リポジトリへ逃がすもの
Settings Sync で設定は数分で戻るのに、認証・インデックス・ローカルLLMは戻らない。マシン買い替え時の Antigravity 環境を三つの層に分け、持ち越す・作り直す・リポジトリへ逃がすの順で整理した実践メモです。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →