observability-driven-testing について
本番環境のオブザーバビリティからテストの不足を特定し、実際のエラーをテストに変えるテストスキルです。トレースによるアサーションとテレメトリーに基づく優先順位付けを組み合わせます。
主な機能
- 01OpenTelemetry テストランナーの設定
- 02トレース構造と遅延の検証
- 03本番エラーからテストへの変換
- 04エラー率に基づくエンドポイントの優先付け
- 05ホットパスのカバレッジ分析
活用シーン
- 01キャッシュ専用リクエストが DB に到達しないことの検証
- 02本番エラーから回帰テストを作成
- 03エラー率とトラフィックによるテスト優先順位付け
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ petrkindlmann/ qa-skills --skill observability-driven-testingインストール後、Claude Code で/observability-driven-testingを入力して読み込まれたか確認します。
同梱ファイルreferences/log-and-error-pipeline.mdreferences/trace-assertions.md
詳細
クイックルート
| 状況 | 移動先 |
|---|---|
| テスト実行時に、アプリと相関するトレースを出力する | OTel テストランナーのセットアップ(references/trace-assertions.md) |
| 呼び出されたサービス/エラースパンがないこと/レイテンシーをアサートする | テストの証拠としてのトレース |
| Sentry/Datadog のエラーをテストに変換する | 本番エラーからテストへのパイプライン |
| 次にテストが必要なエンドポイントを判断する | テレメトリー主導のテスト優先順位付け |
| トレースアサーションが不安定、またはスパンが届かない | 失敗モード |
質問事項
まず .agents/qa-project-context.md を確認します。存在する場合は、その内容をコンテキストとして使用し、すでに回答されている質問は省略します。
オブザーバビリティスタック:
- どの APM/トレースツールを導入していますか?(Datadog、New Relic、Honeycomb、Splunk Observability/SignalFx、ServiceNow Cloud Observability — 旧 Lightstep、Dash0、Jaeger、Grafana Tempo、OpenTelemetry ネイティブ)— トレースの取得方法と、診断ワークフローで使用するクエリ構文が決まります。
- アプリケーションには OpenTelemetry が計装されていますか?また、どのサービスが計装されていますか?— 計装されていないサービスは見えず、トレースによるテストもできません。
- どのようなロギング基盤がありますか?(ELK、Loki、CloudWatch、Datadog Logs)— トレース ID によるログ相関の場所が決まります。
- 構造化ログを使用していますか、それとも自由形式のテキストですか?— 構造化ログはテストの不足箇所に解析できます。自由形式の場合は、まずフィンガープリンティングが必要です。
トレースの成熟度:
- サービス境界をまたぐ分散トレースを利用できますか?— 利用できない場合は、単一サービスのスパンアサーションのみ可能です。
- トレースのサンプリング率はどのくらいですか?(100%、10%、ヘッドベース、テールベース)— 確率的サンプリングでは、テストがアサートするトレースがランダムに破棄されることがあります。テストトラフィックは強制的にサンプリングする必要があります(「失敗モード」を参照)。
- エラーステータス、レイテンシーのしきい値、カスタム属性でトレースを検索できますか?
- トレースはログやメトリクスと相関していますか?— エグザンプラー(メトリクス → 代表的なトレース ID)が利用でき、優先順位付けを具体的に行えます。
本番エラーの追跡:
- どのエラー追跡ツールを使用していますか?(Sentry、SmartBear Insight Hub — 旧 Bugsnag、Rollbar、Datadog Error Tracking、LaunchDarkly Observability — セッションリプレイを含む、旧 Highlight.io)
- 本番エラーはどのようにトリアージしていますか?(自動、手動、無視)
- 本番エラーをテストケースに変換するプロセスはありますか?
- テストで検出できたはずの直近の本番エラーは何ですか?
テストインフラストラクチャ:
- テストからテレメトリーを出力できますか?(トレース、カスタムメトリクス、構造化ログ)
- テスト結果はアプリケーションのテレメトリーと相関していますか?
- テストとコードのカバレッジ対応表はありますか?— 下記のエラー率とカバレッジのマトリクスを算出するために必要です。
基本原則
1. 本番データからテストの優先順位を決める
最も価値のあるテストは、理論上のエッジケースや作為的なシナリオではなく、実際の本番エラーを防ぐテストです。本番環境のエラーログは、実際のユーザーが遭遇した頻度に基づいて並べられた、作成すべきテストの優先順位付きバックログです。
2. トレースはテストの証拠
「API が 200 を返した」ことは、エンドポイントが応答したことを証明します。「リクエストがキャッシュに到達し、データベースをスキップして、<50ms で返された」ことは、あらゆるレイヤーでシステムが正しく動作したことを証明します。トレースを使えば、テストを脆くすることなく、より深くできます。
3. オブザーバビリティの不足はテストの不足に等しい
トレース、ログ、メトリクスがないコードパスは見えません。本番環境でテストできず、インシデント発生時にも検証できません。オブザーバビリティのカバレッジとテストカバレッジは、同じ問題を異なる視点から見たものです。
4. フィードバックループを閉じる
完全なサイクル:エラー検出 → 分析 → テスト作成 → デプロイ → 再発防止。チームが本番環境のエラーを見つけても、体系的にテストを作成しなければ、同じ種類のエラーが再発します。
テストの証拠としてのトレース
@opentelemetry/semantic-conventionsを厳密なバージョンに固定し、sem-conv のバージョン更新は破壊的変更として扱ってください。 トレースアサーションは属性名を文字列で参照するため、リリース間で名前が変わると、アサーションが気付かないうちに壊れます。v1.41.0(2026年4月)では、GenAI の破壊的変更とprocess.executableエンティティの分割が行われ、graphql.documentが Recommended から Opt-In に移行しました。バージョンを固定し、意図的に更新してください:// package.json — 完全固定、キャレットなし "@opentelemetry/semantic-conventions": "1.41.1"npm install --save-exact @opentelemetry/[email protected]新しい OpenTracing 互換レイヤーを導入しないでください。 OTel 仕様では、2026年3月に OpenTracing 互換性が非推奨となりました(削除は早くとも2027年3月以降です)。新しい計装では、ネイティブ OTel API と OTLP を対象にしてください。
references/trace-assertions.md に記載されている3つのパターン:
- テストインフラストラクチャへの OpenTelemetry 統合 — 実際のテストスパンを作成し、
service.name、test.suite、test.run_idを使ってアプリケーションのトレースと 相関させます。同じワーカープロセス内でsdk.shutdown()を初期化して完了を待ちます。コーディネーターのグローバル ティアダウンでは、ワーカーの SDK をフラッシュできません。ワーカーフィクスチャまたはテストプロセスのティアダウンフックを使い、 最後に期待されるスパンがコレクターに到達したことを確認してください。シャットダウンだけでは配信の証明になりません。 - トレースベースのアサーション — HTTP ステータスだけでなく、トレース構造、スパン属性、タイミング(呼び出されたサービス、ERROR スパンがないこと、ルートスパンのレイテンシ、DB 操作)をアサートします。ユニットレベルのスパンチェックには、プロセス内の
InMemorySpanExporter+SimpleSpanProcessorを使い、getFinishedSpans()を同期的に読み取ります。ネットワークもwaitForTraceも不要で、タイムアウトによる不安定さもありません。プロセスをまたぐトレースには、実際のコレクターとwaitForTraceを使う方法を確保してください。 - サービス間の分散トレース検証 — リクエストが期待されるサービスを順番どおりに通過したことを、スパンごとの属性と
maxDurationのチェックとともに検証するassertTraceStructureヘルパーです。
宣言的なトレースベースのアサーション(手書きのスパン検索ではなく、YAML/UI 主導)には、OSS プロジェクトの Tracetest(kubeshop/tracetest)を引き続き利用できます。ただし、公開されている OSS の最新リリースは v1.7.1(2024年10月)で、最近の活動も少ないため、採用前にメンテナンス状況を評価してください。Tracetest の商用 Cloud 提供は2024年10月に終了しました。Tracetest Cloud をセットアップしないでください。ユーザーが終了した製品を利用することになります。
ログを活用したテスト設計
本番環境のエラーログを分析してテストの不足を特定する
本番環境のエラーは、テスト作成における最優先の入力です。未処理のエラーはそれぞれ、テストの不足を示します。references/log-and-error-pipeline.md を参照してください。ここには、各本番エラーをテストカバレッジに対応付け、頻度と新しさに基づいて優先度を割り当て、エラーの特性から適切なテストレイヤー(ユニット/統合/e2e)を提案する analyze-production-errors.ts スクリプトが記載されています。
エラーを分類する:カバー済みと未カバー
1. Export production errors from error tracker (Sentry, Insight Hub, etc.)
- Filter: last 30 days, count > 5 (ignore one-off errors)
- Group by: error message fingerprint
2. For each error group:
a. Does a test exist that would catch this error?
→ Yes: the test is either not running or has a gap (investigate)
→ No: this is a test gap (create a test)
b. What layer should the test live at?
→ TypeError, null reference → unit test
→ Timeout, connection error → integration test with fault injection
→ UI rendering error → E2E test
→ Data inconsistency → contract test or database test
3. Output: prioritized list of tests to create, ordered by:
error frequency × user impact × recency
エラーの頻度と影響度に基づいてテスト作成の優先順位を決める
頻度(高/低)と影響度(高/低)の2×2マトリクスを使って優先順位を付けます。P0 = 高頻度+高影響度(今すぐ修正)、P1 = 低頻度+高影響度(次のスプリント)、P2 = 高頻度+低影響度(今スプリント)、P3 = どちらも低い(バックログ)。影響度の指標:高 = 決済/認証の失敗、データ損失、クラッシュ;低 = UI の不具合、遅いが機能する応答。
テレメトリ主導のテスト優先順位付け
エラーで重み付けしたギャップでエンドポイントをスコアリングする
実際の使用状況と実際の障害に比例して、テストに取り組みます。ギャップスコアは、このスキル全体で使用する標準的な計算式です。
Gap Score = (error_rate × requests_per_day) / max(test_count, 1)
これはエラーで重み付けされます。エンドポイントが生成する失敗リクエストの絶対量を、すでにそれを保護しているテストカバレッジの割合で割って順位付けします。(代わりに、トラフィックが多く健全なエンドポイントを浮き彫りにする、ボリュームで重み付けした見方が必要な場合は、error_rate ではなく (1 + error_rate) を掛けてください。これは別の問いであり、マトリクスのラベルとは異なります。)
エンドポイントごとのエラー率とテストカバレッジの対応付け
Endpoint | Requests/day | Error Rate | Test Count | Gap Score
POST /api/orders | 50,000 | 0.3% | 2 | 75 CRITICAL
PUT /api/profile | 5,000 | 1.2% | 1 | 60 CRITICAL
DELETE /api/items | 2,000 | 0.8% | 0 | 16 HIGH
POST /api/auth | 80,000 | 0.1% | 8 | 10 OK
GET /api/search | 200,000 | 0.05% | 15 | 6.7 OK
Gap Score = (error_rate × requests_per_day) / max(test_count, 1)
Labels: CRITICAL ≥ 50, HIGH 12–49, OK < 12.
Action: create tests for endpoints at HIGH or above, highest score first.
上記の各ラベルは、計算式と明示されたしきい値から導き出されています。計算式をコピーすれば、マトリクスを正確に再現できます。しきい値は自由に設定できますが、必ず明示してください。手作業でラベルを付けてはいけません。
エグザンプラーが、メトリクス → トレース → テストのループを完成させます。 このマトリクスでエラー率の高いエンドポイントが見つかった場合、OTel のエグザンプラーを使うと、エラー率メトリクスから代表的な失敗トレース ID に直接移動し、そのトレースを(以下の手順で)たどってテストを作成できます。一致するトレースを手作業で探す必要はありません。
ホットパス分析
本番環境で最も頻繁に通るコードパスを特定し、それらが通過頻度に見合ったテストカバレッジを備えていることを確認します。
1. Extract top 20 endpoints by request volume from APM data
2. For each endpoint, trace the code path through services
3. Map each service-level span to test coverage data
4. Identify hot paths with zero or low test coverage
Output:
/api/checkout → cart-service → pricing-service → payment-service
Coverage: cart-service (82%) → pricing-service (45%) → payment-service (91%)
Gap: pricing-service discount calculation has 45% coverage on a critical path
Action: Add tests for discount edge cases in pricing-service
エンドポイント単位のトラフィックデータと継続的プロファイリングを組み合わせることで、境界部分だけでなく、エンドポイント内部の CPU とメモリ割り当てのホットパスも特定できます。OTel のプロファイリングシグナルは、2026-03-26 にパブリックアルファ版となりました(OTLP パス
/v1development/profiles)。GA は 2026 年第 3 四半期を目標としているため、まだ本番環境で使える状態ではないものとして扱ってください。現在、本番環境で利用できる代替手段は、Pyroscope、Parca、Polar Signals、Datadog Profilingです。eBPF を使ったゼロインストルメンテーションのプロファイラー(SDK の変更不要)には、Polar Signals、Parca、Grafana のBeylaがあります。
ゼロインストルメンテーションのオブザーバビリティ — OTel SDK を追加できない場合、eBPF ツールを使うと、コードを変更せずにカーネルのシステムコールから HTTP/gRPC トレースを取得できます。Beyla(Grafana)、Cilium Tetragon、Pixie、Corootが該当します。SDK の展開に数四半期かかるレガシーサービスや多言語サービスで役立ちます。
OTel Weaverは、セマンティック規約の YAML から型安全なインストルメンテーションコードを生成し、セマンティック規約のバージョン更新に合わせてトレースのアサーションを同期させます。独自の規約を管理している場合や、バージョン間で属性のずれが発生している場合は、導入する価値があります。
本番エラーからテストへのパイプライン
このスキルで最も重要なワークフローは、本番エラーを再発防止のテストに変えることです。
1. ERROR DETECTED
Source: Sentry, Datadog, CloudWatch, or any error tracker
Capture: error message, stack trace, request context, trace ID, user impact
2. REPRODUCE
- Pull the trace from the observability platform (exemplar → trace ID if available)
- Identify the exact request parameters and state that triggered the error
- Reproduce locally or in staging with equivalent input
- If not reproducible: add targeted logging and wait for recurrence
3. WRITE TEST
- Choose the right layer (unit for logic bugs, integration for service interactions)
- Test must fail before the fix (red-green verification)
- Document the originating production error in the test name or a comment
4. FIX AND DEPLOY
- Fix the bug; verify the test passes with the fix
- Deploy fix + test together
5. VERIFY ELIMINATION
- Monitor the same error in production after deploy
- Confirm error count drops to zero
- If it recurs: the fix was incomplete, repeat from step 2
references/log-and-error-pipeline.md では、Sentry のイシュー PROJ-4521(配送先住所が null → null 参照)をもとに作成したテスト全体を確認できます。このテストでは、API 層で 400 または 422(利用しているコントラクトに応じて)を検証するとともに、E2E のチェックアウトプロンプトを検証します。テスト名とコメントには、発生元のエラー、頻度、コンテキストを記載します。これは、本番環境のシグナルからテストを作成する際に従うべき規約です。
チームのフィードバックループを確立する
- 週次エラーレビュー(30 分): エラートラッカーから、頻度の高い新規エラー上位 10 件を抽出します。それぞれに対して、担当者を割り当てる、テストを作成する、または既知/許容可能なエラーとしてマークします。誰も確認しない未解決エントリーが何千件もあるエラートラッカーは、避けるべきアンチパターンです。
- インシデント終了条件: すべてのポストモーテムに「どのようなテストがあれば防げたか?」を追加します。インシデントを終了する前に、テストを作成するか、ギャップを明示的に記録します。これをチェックリスト項目に紐付け、努力目標ではなく監査可能な項目にします。
診断ワークフロー
失敗したリクエストをエンドツーエンドでトレースする
テストが失敗した場合や本番エラーが発生した場合は、トレースを使って実際に何が起きたかを正確に把握します。
1. Get the trace ID (from test output, error tracker, or user report)
2. Open the trace in your APM tool
- Jaeger: /trace/{traceId}
- Datadog: /apm/traces?traceId={traceId}
- Honeycomb: query by trace.trace_id
3. Walk the span tree
- Root span: what did the user request?
- Child spans: which services were called?
- Error spans: where did it fail? (which span FIRST shows an error)
- Slow spans: where did latency accumulate?
4. Correlate with logs
- Filter logs by trace ID to see every log entry for this request
- Look for warnings or errors that precede the failure
5. Identify the root cause
- Is the error in your code, a dependency, or infrastructure?
- Transient failure or persistent bug?
テストの失敗と本番環境のテレメトリを関連付ける
テストが失敗したら、可観測性プラットフォームにクエリを実行します。(1)本番環境のエラーから、一致するメッセージを検索します(過去7日間)。(2)同じHTTPルートでステータスがERRORのトレースを検索します。一致するものがあれば、バグは実在し、ユーザーに影響しています。修正を優先してください。一致するものがなければ、テスト固有の問題か、まだ本番環境に反映されていない新たなバグである可能性が高いです。これにより、「おそらく不安定」という状態を、「本番環境への影響を確認済み」または「テスト固有の問題」へと変えられます。
アンチパターン
1. 本番環境のシグナルを無視する
エラートラッカーには、誰も確認していない未解決のエラーが500件あります。テストスイートが成功しているため、チームは品質に問題はないと思い込んでいます。**対処法:**上記の週次30分間のエレビューを実施してください。新しいエラーの上位10件それぞれに、担当者、テスト、または既知・許容済みの印を割り当てます。
2. 観測しやすいものだけをテストする
チームはHTTPステータスと応答時間を検証する一方で、データの整合性、バックグラウンドジョブの完了、キャッシュの一貫性を無視しています。**対処法:**バックグラウンドジョブ、キャッシュ操作、非同期ワークフローにスパンを追加し、それらを検証します。本番環境で実行されるものは、テレメトリを生成する必要があります。
3. 本番環境とテストの間にフィードバックループがない
SREがエラーに対応し、QAがテストを作成していますが、どちらも体系的に情報を共有していないため、同じ種類のバグが再発します。**対処法:**本番環境のエラーからテストに至るパイプラインと、インシデントをクローズする際のゲートを確立します。
4. テストを過剰に計装し、データを活用しない
数千件のメトリクスやログを出力しているのに、誰も分析していません。コストがかかるだけで、メリットがありません。**対処法:**テストのテレメトリで回答したい具体的な質問を3つに絞って始めます。それらのダッシュボードを作成し、新たな質問が出てきた場合にのみ計装を追加します。
5. トレースをデバッグにだけ使い、アサーションには使わない
トレースを、障害を防ぐためのアサーションの情報源ではなく、障害発生後のデバッグ用ツールとして扱っています。**対処法:**統合テストにトレースベースのアサーションを追加し、正しいサービスが呼び出されているか、クエリが効率的か、期待どおりにキャッシュがヒットしているかを検証します。これにより、HTTPレベルのアサーションでは見逃すリグレッションを検出できます。
6. 確率的にサンプリングされたトレースを検証する
ヘッドサンプリングまたは確率的サンプリングによって、テストが検証対象としているトレースがランダムに破棄され、断続的な失敗が発生します。**対処法:**テストトラフィックを強制的にサンプリングし(OTEL_TRACES_SAMPLER=always_onまたはリクエスト単位のオーバーライド)、検証対象のトレースがすべて記録されるようにします。
障害モード
| 症状 | 考えられる原因 | 対処法または確認事項 |
|---|---|---|
waitForTrace がタイムアウトし、スパンが届かない | サンプリング、エクスポート、コレクターの保持期間、またはスパンが実際に出力されていない | スパンを出力し、テストトラフィックを保持します。エクスポーター/コレクターで受信したことと実行IDを確認します |
| 最後のテストの末尾のスパンがない | クリーンアップが await されていないか、別のプロセスで実行された | 所有するワーカー内で sdk.shutdown() を await し、コレクターが最後に受信したことを検証します |
| アプリのスパンがテストのトレースに含まれない | アプリが traceparent ヘッダーを伝播していない | アプリがW3C traceparent を読み取り、転送していることを確認します。OTelプロパゲーターの設定を確認します |
db.system/graphql.document/GenAI属性に対するアサーションが突然失敗する | sem-convのバージョン更新で属性名が変更されたか、移動した | @opentelemetry/semantic-conventions のバージョンを厳密に固定し、リリースノートを比較して、意図的にアサーションを更新します |
| CIでコレクターにスパンが届かない | OTEL_EXPORTER_ENDPOINT にCIネットワークから到達できない | CI内のコレクターアドレスを指定します。以下の検証手順でスモークテストを実施します |
実際にエラーがあるのに status?.code === 'ERROR' が何にも一致しない | コレクターがステータスを 'ERROR' ではなく 2/'STATUS_CODE_ERROR' としてシリアライズしている | コレクターが実際に出力する値と一致させます(references/trace-assertions.md の注記を参照) |
検証
トレースに関するアサーションを信頼する前に、まず最小限の確認から始めて、テレメトリの経路が機能することを確かめます。
# 1. Start a local collector, point the runner at it, run one instrumented test.
OTEL_EXPORTER_ENDPOINT=http://localhost:4318/v1/traces \
OTEL_TRACES_SAMPLER=always_on \
npx playwright test --grep @trace
# 2. Confirm a span with service.name=integration-tests arrived at the collector
# (check the collector's debug/logging exporter output, or query your APM).
次に、コード内で、構造に関するアサーションを行う前に、既知のトレース ID を解決できることを確認します。await collector.waitForTrace(traceId, { timeout: 10_000 }) はスパンを返す必要があります。タイムアウトする場合は、アサーションを追加する前に、サンプリング/フラッシュ/伝搬を修正してください(「失敗モード」を参照)。ユニットレベルのスパン確認には、InMemorySpanExporter の経路を使うと、コレクターなしでスパンが同期的に返されます。
完了条件
- トラフィック上位 20 件の各エンドポイント(ホットパスマトリックスに基づく)が、サンプリングされたトレース内で少なくとも 1 つのスパンに解決されること。トラフィックの多いエンドポイントが見えない状態になっていないこと。
- 少なくとも 1 つの主要なユーザージャーニーについて、トレースベースのアサーションがあり、サービス呼び出しとスパン属性を検証していること(HTTP ステータスのみの検証ではないこと)。また、
OTEL_TRACES_SAMPLER=always_onのもとで成功すること。 - 本番環境のエラー分析で明らかになった既知の失敗モードについて、ログに基づいたテストケースがあること。
- エラー率/Gap Score マトリックスが算出され、未テストのコードパスの優先順位付きリストが少なくとも 1 つ作成されていること。
@opentelemetry/semantic-conventionsのバージョンがpackage.jsonで完全に固定されていること(キャレットなし)。- リリースが安定と判断される前にオブザーバビリティのシグナルを確認したことを示す、デプロイ後レビューの記録(チェックリスト項目またはポストモーテムの記載)があること。
参考ファイル(references/ 内)
- trace-assertions.md — OTel テストランナーの設定(正しいグローバルティアダウン時のフラッシュとインメモリーエクスポーターの代替手段を含む)、強制サンプリングに関する注記、トレースベースのアサーション、および分散型の
assertTraceStructureヘルパー。 - log-and-error-pipeline.md —
analyze-production-errors.tsのテストギャップ検出スクリプトと、本番環境のエラーからテストを作成する具体例(400 または 422 のアサーション)。
関連スキル
- testing-in-production — リリース中の安全なロールアウト手法(フラグ、カナリア、ガードレール指標)を扱います。このスキルでは、そうしたリリースで生成されたテレメトリを入力として、リリース後にテストを設計します。
- synthetic-monitoring — リリース後に実行され、自らテレメトリを出力する定期プローブを扱います。そのテレメトリをここでの分析に使用します。
- qa-metrics — テレメトリから得た数値(エラー率、レイテンシ、Gap Score)を品質ダッシュボードや KPI に反映します。このスキルは元となるシグナルを生成し、qa-metrics が集計します。
- ai-bug-triage — 分類して振り分ける必要のある CI/本番環境の障害が大量にある場合に使用します。エラー分類の手順に情報を渡した後、テストの作成に戻ります。