📚 この記事は「OpenAI Codex CLI 完全攻略シリーズ」の Episode 13 です。
テスト自動化は、ソフトウェア開発において品質保証の要です。しかし現実のSES現場では、テストコードの作成に十分な時間が取れないことが多く、テストカバレッジが低いまま運用されているプロジェクトも少なくありません。
OpenAI Codex CLIを使えば、既存コードからユニットテストを自動生成し、テスト実行からカバレッジ改善まで一気通貫で行うことができます。本記事では、Codex CLIによるテスト自動化の実践テクニックを、具体的なコード例とともに解説します。

なぜCodex CLIでテスト自動化するのか
SES現場のテスト課題
SESエンジニアが直面するテストに関する典型的な課題は以下の通りです。
- テスト工数が確保できない: 納期優先でテストコードが後回しになる
- レガシーコードにテストがない: 既存システムの保守案件でテストが一切ない
- テストパターンの網羅が難しい: エッジケースの洗い出しに時間がかかる
- テストコードの品質が属人的: 人によってテストの書き方がバラバラ
Codex CLIは、これらの課題をAIの力で一気に解決します。
Codex CLIのテスト生成が優れている理由
- コード理解力: ソースコードを読み取り、関数の入出力・副作用を理解してテストを生成
- パターン網羅: 正常系・異常系・境界値テストを自動的に洗い出す
- フレームワーク対応: Jest、pytest、JUnit、RSpecなど主要テストフレームワークに対応
- 一貫性: チーム全体で統一されたテストスタイルを維持
Codex CLIでのテスト生成:基本ワークフロー
ステップ1:対象ファイルの指定
まず、テストを生成したいソースファイルを指定してCodex CLIに依頼します。
codex "src/utils/calculator.ts のユニットテストを生成してください。
Jest を使い、正常系・異常系・境界値テストを網羅してください。"
ステップ2:生成されたテストの確認
Codex CLIが生成するテストの例を見てみましょう。
// src/utils/calculator.test.ts
import { Calculator } from './calculator';
describe('Calculator', () => {
let calc: Calculator;
beforeEach(() => {
calc = new Calculator();
});
describe('add', () => {
// 正常系
it('正の整数同士の加算ができること', () => {
expect(calc.add(2, 3)).toBe(5);
});
it('負の数を含む加算ができること', () => {
expect(calc.add(-1, 5)).toBe(4);
});
it('小数の加算ができること', () => {
expect(calc.add(0.1, 0.2)).toBeCloseTo(0.3);
});
// 境界値
it('ゼロ同士の加算', () => {
expect(calc.add(0, 0)).toBe(0);
});
it('最大安全整数付近の加算', () => {
expect(calc.add(Number.MAX_SAFE_INTEGER, 0))
.toBe(Number.MAX_SAFE_INTEGER);
});
// 異常系
it('NaNが渡された場合', () => {
expect(calc.add(NaN, 1)).toBeNaN();
});
it('Infinityが渡された場合', () => {
expect(calc.add(Infinity, 1)).toBe(Infinity);
});
});
describe('divide', () => {
it('正常な除算ができること', () => {
expect(calc.divide(10, 2)).toBe(5);
});
it('ゼロ除算でエラーがスローされること', () => {
expect(() => calc.divide(10, 0)).toThrow('Division by zero');
});
it('負の数の除算', () => {
expect(calc.divide(-10, 2)).toBe(-5);
});
});
});
Codex CLIは、関数のシグネチャと実装を分析して、適切なテストケースを自動生成します。特に境界値テスト(NaN、Infinity、MAX_SAFE_INTEGER)を自動で含めてくれる点が優秀です。
ステップ3:テスト実行と結果確認
codex "生成したテストを実行して、結果を確認してください。
失敗するテストがあれば修正してください。"
Codex CLIは full-auto モードでテストを実行し、失敗したテストを自動修正します。
実践テクニック1:既存コードのテスト追加
プロジェクト全体のテストカバレッジ向上
codex "このプロジェクトのテストカバレッジを確認し、
カバレッジが低いファイル上位5つにユニットテストを追加してください。
目標カバレッジは80%以上です。"
Codex CLIは以下の手順で作業を進めます。
npx jest --coverageでカバレッジレポートを生成- カバレッジが低いファイルを特定
- 各ファイルのテストを自動生成
- テストを実行してパスすることを確認
- カバレッジが目標に達したか再確認
ディレクトリ単位でのバッチ生成
codex "src/services/ ディレクトリ内の全ファイルに対して
ユニットテストを生成してください。
テストファイルは src/services/__tests__/ に配置してください。"
大量のファイルに対してテストを一括生成する場合、Codex CLIの full-auto モードが特に効果的です。
実践テクニック2:テストパターン別の生成
APIエンドポイントのテスト
codex "src/controllers/userController.ts のAPIテストを生成してください。
supertest を使い、以下のエンドポイントをテストしてください:
- GET /api/users
- POST /api/users
- PUT /api/users/:id
- DELETE /api/users/:id
正常系・認証エラー・バリデーションエラーのケースを含めてください。"
生成されるテスト例:
import request from 'supertest';
import { app } from '../app';
import { prisma } from '../lib/prisma';
describe('User API', () => {
beforeEach(async () => {
await prisma.user.deleteMany();
});
describe('GET /api/users', () => {
it('200: ユーザー一覧を返す', async () => {
await prisma.user.create({
data: { name: 'テスト太郎', email: '[email protected]' }
});
const res = await request(app)
.get('/api/users')
.set('Authorization', 'Bearer valid-token');
expect(res.status).toBe(200);
expect(res.body).toHaveLength(1);
expect(res.body[0].name).toBe('テスト太郎');
});
it('401: 認証なしでアクセスした場合', async () => {
const res = await request(app).get('/api/users');
expect(res.status).toBe(401);
});
});
describe('POST /api/users', () => {
it('201: ユーザーを作成できる', async () => {
const res = await request(app)
.post('/api/users')
.set('Authorization', 'Bearer valid-token')
.send({ name: '新規ユーザー', email: '[email protected]' });
expect(res.status).toBe(201);
expect(res.body.name).toBe('新規ユーザー');
});
it('400: メールアドレスが不正な場合', async () => {
const res = await request(app)
.post('/api/users')
.set('Authorization', 'Bearer valid-token')
.send({ name: 'テスト', email: 'invalid-email' });
expect(res.status).toBe(400);
expect(res.body.error).toContain('email');
});
it('409: メールアドレスが重複した場合', async () => {
await prisma.user.create({
data: { name: '既存', email: '[email protected]' }
});
const res = await request(app)
.post('/api/users')
.set('Authorization', 'Bearer valid-token')
.send({ name: '新規', email: '[email protected]' });
expect(res.status).toBe(409);
});
});
});
データベース操作のテスト
codex "src/repositories/userRepository.ts のテストを生成してください。
テスト用のデータベース接続を使い、トランザクションのロールバックで
テスト間のデータ汚染を防いでください。"
React コンポーネントのテスト
codex "src/components/UserForm.tsx のテストを生成してください。
React Testing Library を使い、以下をテストしてください:
- フォームの初期表示
- 入力値の変更
- バリデーションエラーの表示
- フォーム送信の成功/失敗"
実践テクニック3:テスト品質の向上
モックの自動設定
Codex CLIは外部依存関係のモックも自動で設定してくれます。
codex "src/services/emailService.ts のテストを生成してください。
外部のSMTPサーバーはモックしてください。
nodemailer のモック設定も含めてください。"
パラメタライズドテスト
codex "src/utils/validator.ts のバリデーション関数に対して、
パラメタライズドテストを生成してください。
多数の入力パターンを効率的にテストしたいです。"
生成例:
describe('validateEmail', () => {
it.each([
['[email protected]', true],
['[email protected]', true],
['[email protected]', true],
['', false],
['not-an-email', false],
['@example.com', false],
['user@', false],
['[email protected]', false],
['user @example.com', false],
])('validateEmail("%s") should return %s', (input, expected) => {
expect(validateEmail(input)).toBe(expected);
});
});
スナップショットテスト
codex "src/components/ 配下のReactコンポーネントに
スナップショットテストを追加してください。
UIの意図しない変更を検出できるようにしてください。"
実践テクニック4:テスト実行の自動化
ファイル監視モードでの継続テスト
codex "package.json に以下のnpm scriptsを追加してください:
- test:watch - ファイル変更時に関連テストを自動実行
- test:coverage - カバレッジレポート生成
- test:ci - CI環境用のテスト実行(JUnit形式のレポート出力)"
pre-commit hookでのテスト自動実行
codex "husky と lint-staged をセットアップして、
コミット前に変更ファイルに関連するテストを自動実行する
設定を追加してください。"
実践テクニック5:Pythonプロジェクトでのテスト生成
pytest でのテスト自動生成
codex "src/services/order_service.py のユニットテストを
pytest で生成してください。
fixture を使ったテストデータの準備、
parametrize を使ったパラメタライズドテストを含めてください。"
生成例:
import pytest
from unittest.mock import Mock, patch
from src.services.order_service import OrderService
from src.models.order import Order, OrderStatus
@pytest.fixture
def order_service():
db = Mock()
return OrderService(db=db)
@pytest.fixture
def sample_order():
return Order(
id=1,
user_id=100,
total=5000,
status=OrderStatus.PENDING
)
class TestOrderService:
def test_create_order_success(self, order_service):
"""正常に注文を作成できること"""
result = order_service.create_order(
user_id=100,
items=[{"product_id": 1, "quantity": 2}]
)
assert result.status == OrderStatus.PENDING
assert result.user_id == 100
def test_create_order_empty_items(self, order_service):
"""空の商品リストでエラーになること"""
with pytest.raises(ValueError, match="items cannot be empty"):
order_service.create_order(user_id=100, items=[])
@pytest.mark.parametrize("total,expected_discount", [
(1000, 0),
(5000, 250),
(10000, 1000),
(50000, 7500),
])
def test_calculate_discount(self, order_service, total, expected_discount):
"""金額に応じた割引が正しく計算されること"""
discount = order_service.calculate_discount(total)
assert discount == expected_discount
@patch('src.services.order_service.send_notification')
def test_confirm_order_sends_notification(self, mock_notify, order_service, sample_order):
"""注文確定時に通知が送信されること"""
order_service.confirm_order(sample_order)
mock_notify.assert_called_once_with(
user_id=sample_order.user_id,
message=f"注文 #{sample_order.id} が確定されました"
)
テストカバレッジ改善の戦略
カバレッジレポートの分析
codex "テストカバレッジレポートを分析し、
カバレッジが低い領域を特定してください。
特に以下の観点で改善計画を提案してください:
1. ブランチカバレッジが低い条件分岐
2. テストされていないエラーハンドリング
3. エッジケースが未テストの関数"
段階的なカバレッジ改善
SES案件では一度に全てのテストを書く時間はありません。以下の優先順位で段階的に改善しましょう。
- ビジネスロジック層: 最も重要。計算・バリデーション・状態遷移
- データアクセス層: CRUD操作、クエリの正確性
- API層: エンドポイントの入出力、エラーレスポンス
- ユーティリティ関数: 共通処理、ヘルパー関数
- UIコンポーネント: ユーザー操作、表示ロジック
codex "以下の優先順位でテストを追加してください:
1. src/services/ - ビジネスロジック(最優先)
2. src/repositories/ - データアクセス
3. src/controllers/ - API層
目標: 各層のカバレッジ80%以上"
CI/CDパイプラインとの統合
GitHub Actionsでのテスト自動実行
# .github/workflows/test.yml
name: Test
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
- run: npm ci
- run: npm test -- --coverage --ci
- uses: codecov/codecov-action@v4
with:
file: ./coverage/lcov.info
カバレッジしきい値の設定
// jest.config.js
{
"coverageThreshold": {
"global": {
"branches": 80,
"functions": 80,
"lines": 80,
"statements": 80
}
}
}
SES現場でのテスト自動化事例
事例1:レガシーJavaプロジェクト
テストゼロのJavaプロジェクトにCodex CLIでテストを追加した事例です。
codex "src/main/java/com/example/service/ 配下の
Java サービスクラスに対してJUnit 5のテストを生成してください。
Mockito でDI依存関係をモックしてください。"
結果: 2週間で50ファイル・200テストケースを生成。カバレッジ0%→65%に改善。
事例2:リアルタイムデータ処理システム
codex "src/processors/ 配下のデータ処理関数のテストを生成してください。
大量データ(10万件)での性能テストも含めてください。
テストデータはファクトリパターンで生成してください。"
事例3:マイクロサービスの統合テスト
codex "docker-compose.test.yml を使った統合テスト環境をセットアップし、
サービス間のAPI呼び出しをテストするスイートを生成してください。"
Codex CLIのテスト生成オプション
full-autoモードでの完全自動化
codex --approval-mode full-auto \
"src/ 配下の全ファイルにユニットテストを生成し、
全テストがパスすることを確認してください"
full-auto モードでは、Codex CLIが自律的にファイルの作成・編集・コマンド実行を行い、テストがパスするまで修正を繰り返します。
suggestモードでの対話的生成
テスト戦略を相談しながら進めたい場合は、suggest モードが適しています。
codex --approval-mode suggest \
"このプロジェクトのテスト戦略を提案してください"
まとめ:Codex CLIでテスト自動化を加速する
Codex CLIのテスト自動化は、SESエンジニアにとって最もROIが高いAI活用法の一つです。
実践チェックリスト
- プロジェクトのテストフレームワークを選定・設定
- ビジネスロジック層のテストをCodex CLIで生成
- カバレッジレポートを確認し、目標を設定
- CI/CDパイプラインにテスト自動実行を組み込み
- pre-commitフックでテストを強制
- 定期的にカバレッジを確認し、改善
関連記事
OpenAI Codex CLI 完全攻略シリーズ一覧はこちら