/note/tech

40,000行のAPIテスト作成で学んだClaude Code Skillsの育て方

要約:

■ 1. 背景と目的

  • APIの動作保証にシナリオテストツール「runn」を使用していたが、サービス成長に伴うAPI増加により運用が困難になった
  • 1ファイルあたりのステップ数が膨張し、テストの追加・修正が心理的・技術的に高コストな作業となっていた
  • テストを以下の2種類に整理し直し、Claude Code + Skillsで生成する方針を採用した:
    • API単位テスト: 1ファイル = 1API、正常系・異常系を網羅的にカバー
    • ユースケースシナリオ: 複数APIにまたがる業務フローのE2Eテスト

■ 2. テスト生成の仕組み

  • API単位テストのフローは5ステップで構成:
    • Step 1 情報収集: API定義やバリデーションロジックなど関連コードを読み込む
    • Step 2 テストケース洗い出し: コードからエラーハンドリングを網羅的に抽出し正常系・バリデーション・権限・存在チェックなどのケース一覧にまとめる
    • Step 3 ユーザー承認: テストケース一覧をMarkdownで提示し過不足を確認する
    • Step 4 サブエージェントへの委譲: API単位で分割して渡し、ファイル生成・実行・エラー修正を自律的に繰り返させる
    • Step 5 セルフレビュー: チェックリスト(ファイル形式・テスト構造・命名規則)で品質を確認する
  • サブエージェントへの委譲はAPI単位で分割するルールとし、一度に渡すとコンテキストが膨れてテスト品質が低下するため採用した

■ 3. スキルの段階的な改善

  • Phase 1 基本構成の確立: 最初の数APIで基本構造と命名規則を決定し、生成フローの大枠のみを定義したシンプルなスキルを作成
  • Phase 2 runnスキルの切り出し: Claudeが繰り返す同一のrunn記法ミスのパターンが可視化されたため、runn記法ナレッジを独立スキルとして切り出した
  • Phase 3 サブエージェント導入と構造再設計: 1セッションで情報収集から実装・実行まで担う構成ではコンテキスト超過が頻発したため、スキル本体(情報収集・テストケース設計・ユーザー承認)とサブエージェント(ファイル生成・テスト実行・エラー修正)に役割を分離した
  • スキルの見通し改善として、テンプレートやチェックリストを参照ファイルに外出しし、スキル本体(SKILL.md)はフローの記述に集中させた

■ 4. ぶつかった壁と解決策

  • runnはYAMLベースの独特な記法を持ち、LLMにとって馴染みが薄く頻繁にミスが発生した
  • 主な記法ミスのパターン:
    • bind と include の実行順序: 同ステップ内でbindとincludeを書くと、bindの変数がincludeに渡らない
    • testフィールドのアサーション記法: expr-langの関数を知らず存在しない関数(例: startsWith)を使用してしまう
  • 最大の課題はrunnのエラー出力をClaudeが読めないことだった:
    • assertionの条件式が&&や||で組まれると、ツリー構造で深くネストされたエラーが出力される
    • 人間なら失敗箇所を容易に特定できるが、Claudeにはツリーの葉から「=> false」を探す困難な作業になる
    • 結果として、Claudeがツリーを読み解けず同じテストを何度も再実行する悪循環が発生した
  • 解決策としてアサーションをステップに分離する設計を採用:
    • 1つのtest:に全条件を詰め込まず、フィールドごとに独立したステップに分離する
    • 効果1: エラー出力がシンプルになり1ステップ=1条件でツリーのネストが発生しない
    • 効果2: ステップ名で失敗箇所が一目瞭然になる
    • 効果3: Claudeが失敗したverifyステップ名から修正箇所を正確に特定し自律的に修正できる
  • 人が手動でテストを書く場合は記述量を抑えるためアサーション分割を避けることが多いが、LLMにテストを書かせる場合は自律的な修正・デバッグの実現が大きな価値を持つ

■ 5. 振り返りと学び

  • うまくいったこと:
    • 段階的改善: 最初から完璧を目指さず数サービス実装後にパターンを抽出するサイクルが効果的だった
    • 委譲単位の制御: API単位でサブエージェントに渡すことでコンテキスト超過を防ぎテスト品質を維持できた
    • 暗黙知の明文化: Claudeが間違えるたびにNGパターン/OKパターンとしてスキルに蓄積し、LLMが「暗黙知の検出器」として機能した結果、スキルがテスト設計のナレッジベースになった
  • 次への学び:
    • 初期設計のコスト: 最初の数サービスは試行錯誤が多いが、実際にやってみないと見えないパターンも多い
    • サブエージェントのモデル選択: Sonnetを使用したがスキルの指示に従わないケースや同じミスを繰り返すケースがあり、チェックリスト強化やプロンプト調整で対処が必要だった

■ 6. まとめ

  • 約2週間でYAMLベース40,000行超のAPIシナリオテストをClaude Code + Skillsで生成した(数十API対象・100ファイル以上)
  • 取り組みから得た4つのポイント:
    • スキルは最初から完成形を目指さず実装しながら段階的に改善する
    • LLMが間違えるポイントをNGパターン/OKパターンとしてスキルに蓄積する
    • LLMにとって読みにくいエラー出力はテスト設計側の工夫で回避する
    • スキルの改善プロセスは暗黙知を形式知に変換するプロセスそのもの
  • テストの量産だけでなくテスト設計のナレッジが明文化されたことがこの取り組みの最大の成果