OpenAPI仕様とコードが乖離した場合のAPIテスト方法

Rui Li
OpenAPI仕様とコードが乖離した場合のAPIテスト方法 カバー

OpenAPI仕様は信頼できる唯一の情報源であるべきです。しかし実際には、AIコーディングエージェントがバックエンドの変更を積極的にリリースしているコードベースにおいて、仕様はAPIが現在返すものではなく、かつてどのような姿だったかのスナップショットであることがよくあります。実際に動作しているAPIではなく仕様に対してテストを行うことは、すでに一部が誤っている記述に対してテストを行うことを意味します。

なぜ仕様は誰も気づかないうちにドリフトするのか

仕様がドリフトする理由は、誰かが不注意だったこととは何の関係もありません。AIコーディングエージェントがレスポンスにフィールドを追加しても、仕様の更新は与えられたタスクに含まれていなかったためYAMLファイルを更新しようとは思いません。リファクタリングで新しく作成されたリソースのステータスコードが200から201に変更されますが、技術的にはより正確であるものの、仕様はまだ200と記述されています。シリアライザーがキャメルケースからスネークケースへの命名規則を適用しますが、その規則を最初から反映するように仕様は書かれていませんでした。

これらはどこにもエラーとして表示されません。コードは動作し、エンドポイントはレスポンスを返します。そして、真実と記述が食い違うのは、誰も積極的に確認していないドキュメントの中だけです。

仕様からテストが生成された場合に何が起こるか

OpenAPIドキュメントから直接生成されたテストは、誤っている部分も含めて、ドキュメントの記述をそのまま引き継ぎます。仕様がフィールドを必須と記述しているのに、実際に動作しているAPIが最近の変更でそれをオプションにしていた場合、生成されたテストはAPIがもはや従っていないルールを強制します。仕様にAPIが現在返すフィールドが欠けている場合、生成されたテストはそのフィールドの存在を知らないため、単純にチェックを行いません。

これにより、特定の、不満の残る失敗パターンが生まれます。仕様とは内部的に一貫しているものの、APIが実際に何をするかとは完全に切り離されたテストです。グリーンのスイートはAPIが正しいことを意味しません。APIが、それ自体正しくない可能性のある記述と一致していることを意味するだけです。

ドキュメントではなく、動作しているAPIをテストする

解決策は、より優れた仕様解析ツールではありません。仕様以外のもの、つまり実際に動作しているAPIを直接観察してテストすることです。

TestSpriteのBackend Testing 2.0はこの方法で機能します。OpenAPIドキュメントからアサーションを生成するのではなく、エージェントが各実際のエンドポイントを呼び出し、実際のフィールド名、実際のステータスコード、実際のレスポンスの形状など、実際に返ってくるものを記録し、その観察からテストカバレッジを構築します。

他の検証ツールはコードを読んで推測します。TestSpriteはあなたのアプリを開いて実際に使います。

仕様が存在する場合、意図された構造を理解するための有用なコンテキストとして引き続き活用できます。しかし、アサーション自体は、3スプリント前のドキュメントがどうあるべきと記述しているかではなく、APIが実際に何をするかに基づいています。両者が一致しない場合、観察された挙動がテスト対象となり、その不一致はサイレントなギャップとしてではなく、特定の確認可能な調査結果として可視化されます。

シナリオ:仕様がフィールド型について誤りを記述していた調達プラットフォーム

B2B調達プラットフォームを構築するチームは、発注書承認APIのOpenAPI仕様を管理していますが、これはエンドポイントが単純な承認者IDを文字列として返していた時代に作成されたものです。それ以来、AIコーディングエージェントがマルチレベルの承認チェーンをサポートするようにエンドポイントを拡張し、承認者フィールドは現在、承認者のID、役割、承認シーケンス番号を含む構造化されたオブジェクトを返すようになっています。単なる文字列ではありません。

誰も仕様を更新しませんでした。依然として承認者を文字列として記述しています。

開発者は、古くなったドキュメントからテストを再生成するのではなく、TestSpriteをライブAPIに対して実行します。探索エージェントが発注書を送信し、承認レスポンスを確認して、実際の構造を観察します。それは文字列ではなくオブジェクトです。テストはその観察から構築されているため、仕様から派生したテストのように型の不一致で失敗したり、緩い型指定の仕様から派生したテストのように浅いチェックを静かに通過させたりするのではなく、オブジェクトの形状、つまり承認者ID、役割、シーケンス番号がすべて存在し正しい型を持っているかどうかを正しく検証します。

開発者はまた、テスト自体とは独立した有用な情報として、承認者の観察されたレスポンス形状が仕様ファイルで宣言された型と一致しないという具体的な注記を結果で得られます。実際の構造も参照用にドキュメント化されています。これは、誰かが手作業でドキュメントをAPIと照合しなくても、仕様のどこを更新すべきかを正確に示すため、テスト自体とは独立して有用です。

仕様書をそのまま信頼の源泉とすべき場面の見極め方

仕様書に厳密に準拠してテストを行うことが適切なケースも存在します。特に、現在の実装がどうあれ文書化されたコントラクトに依存する外部コンシューマーを持つパブリック APIの場合がそれにあたります。そのような状況では、仕様書からの逸脱がバグであり、たとえ実行中のコードが内部的に一貫していたとしても変わりません。

重要な区別は、その API が誰のために存在するかという点です。自社のフロントエンドや管理下にあるサービスのみが利用する内部 API であれば、観測された動作を直接テストする方がほぼ常に有用です。目標はシステム全体が連携して動作することの確認であり、ドキュメントへの準拠確認ではないからです。一方、外部インテグレーターが利用するパブリック API の場合、仕様準拠そのものがテスト対象の要件となり、新しい動作の方が正しく見えるとしても、逸脱はコントラクト違反として扱われるべきです。

仕様書と実態のさらなる乖離を防ぐために

実行中の API をテストすることで、乖離が発生した後にそれを検出できます。乖離が拡大し続けるのを防ぐためには、TestSprite が明らかにするギャップ、すなわち観測された動作と文書化された動作の差異を、単に記録するだけでなく対処すべき問題として捉えることが必要です。

このチェックを AI コーディングセッション後のトリガー「Help me test this project with TestSprite」と同じタイミングで実行すれば、Claude Code または Cursor 内の MCP Server を通じて、変更が加えられたセッションの中で乖離を検出できます。新しい動作と古い仕様のどちらが正しいかを判断するためのコンテキストが、まだ新鮮なうちに対応できます。

まとめ

OpenAPI 仕様書は API の説明であり、API そのものではありません。そして説明は、誰も気づかないまま陳腐化していきます。その影響が顕在化するのは、誤った前提に基づいて作成されたテストが、誤った理由で失敗するか、本来失敗すべき場面でパスしてしまったときです。

TestSprite は API が実際に返すレスポンスをテストし、文書化された仕様との乖離を検出します。そして、どちらが正しいかの判断はチームに委ね、ドキュメントが常に正しいとは仮定しません。

TestSprite で実際の API をテストし、仕様の誤りを本番インシデントで知るという事態をなくしましょう。