はじめに
Contract Test(契約テスト)は、「入口の仕様(ルーティング、ヘッダ、リダイレクト、エラー時の振る舞いなど)を壊さない」ための強力な安全装置です。ところが、テストを回して 落ちた瞬間 によく起きるのがこの状況です。
- CIが赤いのは分かるけど、どこが壊れたのか読み解くのが面倒
- ログが長い/並列で流れて見づらい
- “前回は通った” という事実しかなく、比較ができない
- 失敗の再現に時間がかかる(手元では通う、など)
ここで効くのが テスト結果のアーティファクト化 です。
要するに、テストの「証拠」を 誰でも見られる形 に落として残す。これだけで、契約テストは“あると安心”から“運用で本当に役に立つ”へ変わります。
この記事では、入口のContract Testを例にしつつ、
- Playwright:HTMLレポート/スクショ/トレース/JUnit
- k6:サマリ出力(JSON/CSV)と閾値の結果
- CI(例:GitHub Actions):成果物をArtifactsとして保存
- メトリクス化:時系列で「劣化」「改善」を追えるようにする
を、最小構成から段階的に作ります。
座学
1) “アーティファクト化”のゴールは、原因究明のコストを下げること
テストを増やすだけだと、失敗時の確認コストも増えます。
アーティファクト化の目的はシンプルで、「誰が見ても、短時間で原因が分かる」状態にすることです。
入口のContract Testで特に残したい情報は次の4つです。
- 何が落ちたか(テスト名/失敗箇所)
- どう落ちたか(期待 vs 実際、HTTP status、ヘッダ差分、レスポンス)
- いつから落ちたか(前回との比較、初回失敗のコミット)
- 性能・安定性がどう変わったか(p95、失敗率、スループット)
これが揃うと、入口の変更(Nginx設定など)でも “調べる” より “直す” に時間が使えます。
2) HTMLレポートとメトリクスは役割が違う
HTMLレポートは、失敗時の「現場写真」です。
- どのテストが落ちたか
- エラーメッセージ、スタックトレース
- スクリーンショット、ネットワークの痕跡(Playwrightならtrace)
**メトリクス(時系列)**は、「体調管理」です。
- 今回のp95が悪いのは偶然?それとも継続劣化?
- 失敗率がじわじわ上がっていないか
- 設定変更で“改善した”ことを証明できるか
入口のContract Testは、仕様の破壊だけでなく、じわじわ劣化(タイムアウト増、p95悪化)も重大事故の前兆になります。だから「写真(HTML)」と「体調(メトリクス)」の両方が必要です。
3) 実装の勘所:残すべき成果物を最初から決める
おすすめの最小セットはこれです。
- Playwright:
HTML report+trace(失敗時)+screenshot(失敗時)+JUnit(CI向け) - k6:
summary JSON+threshold result(失敗したら落とす) + 可能ならCSV(後で比較しやすい)
そしてCIでは、
- 成果物を Artifactsとしてアップロード
- できれば PRにリンク(見に行ける導線)
- さらに余力があれば 時系列DBへ送る(Prometheus/Influx等)
この順番が現実的です。最初から大掛かりにすると運用が止まりやすいので、段階的に強化します。
ハンズオン
前提として、入口(Nginx)が http://localhost:8088 にあり、Contract Testを Playwright と k6 で実行している状況を想定します。ここでは「成果物を残す」ことに集中します。
1) Playwright:HTMLレポート/トレース/スクショを“失敗時だけ”残す
(1) playwright.config を成果物向けに設定
e2e/playwright/playwright.config.js の例です。
import { defineConfig } from "@playwright/test";export default defineConfig({
testDir: "./tests",
retries: 0,
use: {
baseURL: process.env.BASE_URL || "http://localhost:8088", // 失敗時に証拠を残す(常時ONだと重くなる)
screenshot: "only-on-failure",
trace: "retain-on-failure",
video: "retain-on-failure",
}, // HTMLレポート(CIで artifacts 化しやすい)
reporter: [
["html", { outputFolder: "playwright-report", open: "never" }],
// CIでテスト管理と相性が良い(任意)
["junit", { outputFile: "test-results/junit.xml" }],
["list"],
], // 失敗時のログを見やすくしたい時に有効(必要なら)
// workers: 1,
});
これで、失敗したときだけ
- スクリーンショット
- トレース(trace.zip)
- 動画
が残り、HTMLレポートに紐づきます。
(2) 実行
npx playwright test
成果物は主に次に出ます。
e2e/playwright/playwright-report/(HTMLレポート)e2e/playwright/test-results/(trace、screenshot、video、JUnit等)
(3) ローカルでHTMLレポート確認
npx playwright show-report playwright-report
“どこで壊れたか”が一発で追えるようになります。入口周りはHTTPテスト中心でも、これがあると原因特定が劇的に速くなります。
2) k6:サマリをJSONで残して、比較できる形にする
k6は「実行結果がコンソールに出て終わり」だと、比較が難しいです。そこで サマリJSON を毎回保存します。
(1) サマリをファイルに出す(handleSummary)
e2e/k6/entry.js に handleSummary を追加します。
import http from "k6/http";
import { check, sleep } from "k6";export const options = {
vus: 20,
duration: "20s",
thresholds: {
http_req_failed: ["rate<0.01"],
http_req_duration: ["p(95)<400"],
},
};const BASE_URL = __ENV.BASE_URL || "http://host.docker.internal:8088";export default function () {
const res1 = http.get(`${BASE_URL}/`);
check(res1, {
"GET / is 200": (r) => r.status === 200,
}); const res2 = http.get(`${BASE_URL}/api/health`);
check(res2, {
"GET /api/health is 200": (r) => r.status === 200,
}); sleep(0.2);
}// ここがポイント:実行結果をJSONで吐く
export function handleSummary(data) {
return {
"k6-summary.json": JSON.stringify(data, null, 2),
};
}
(2) 実行してファイルができることを確認
docker run --rm -i grafana/k6 run - < e2e/k6/entry.js
実行ディレクトリに k6-summary.json が生成されます(CIではワークスペースに残る)。
このJSONがあるだけで、後から p95 や失敗率を抽出して比較できるようになります。
3) CIで“成果物として保存”する(例:GitHub Actions)
ここでは、CIが何であっても考え方は同じで、
- テストを実行
- レポートディレクトリやサマリJSONを生成
- それらをArtifactsとしてアップロード
という流れです。
(1) GitHub Actions の例(最低限)
.github/workflows/contract-test.yml の例です(概念を掴む用)。
name: contract-teston:
pull_request:
push:
branches: [ main ]jobs:
e2e:
runs-on: ubuntu-latest steps:
- uses: actions/checkout@v4 - name: Start stack (Nginx + API)
run: |
docker compose -f docker-compose.yml -f docker-compose.go.yml up -d --build - name: Setup Node
uses: actions/setup-node@v4
with:
node-version: "20" - name: Install Playwright deps
working-directory: e2e/playwright
run: |
npm ci || npm install
npx playwright install --with-deps - name: Run Playwright
working-directory: e2e/playwright
env:
BASE_URL: http://localhost:8088
run: npx playwright test - name: Run k6
run: |
docker run --rm -i -e BASE_URL=http://host.docker.internal:8088 grafana/k6 run - < e2e/k6/entry.js - name: Upload Playwright report
if: always()
uses: actions/upload-artifact@v4
with:
name: playwright-report
path: e2e/playwright/playwright-report - name: Upload Playwright test-results (trace/screenshot/video/junit)
if: always()
uses: actions/upload-artifact@v4
with:
name: playwright-test-results
path: e2e/playwright/test-results - name: Upload k6 summary
if: always()
uses: actions/upload-artifact@v4
with:
name: k6-summary
path: k6-summary.json - name: Shutdown stack
if: always()
run: docker compose -f docker-compose.yml -f docker-compose.go.yml down -v
重要なのは if: always() です。
失敗したときほどレポートが欲しいので、落ちてもアップロードされるようにします。
これでPRから
- Playwright HTMLレポート
- traceやスクショ
- k6のsummary JSON
をダウンロードできるようになり、「壊れた理由の共有」が一気にラクになります。
4) メトリクス化の第一歩:k6 JSONから“必要な数値だけ”抜き出して保存
時系列DBに送る前に、まずは 比較可能な1枚のJSON を作るのが現実的です。例として、k6 summaryから次を抜くイメージです。
- 失敗率(http_req_failed)
- p95(http_req_duration p(95))
- 平均(avg)
- 直近コミットSHA(CIの環境変数で入れる)
CIの中で軽く整形して metrics.json を成果物にするだけでも、「前回より悪くなった」を議論しやすくなります。
(この段階ではDBは要りません。まず“比較しやすい形”にするのが勝ちです。)
5) 本格的に“時系列化”するなら:k6 → Prometheus/Influx → Grafana
余力が出たらここに進みます。代表ルートは2つです。
- InfluxDBルート:k6の出力先として有名で、導入が比較的分かりやすい
- Prometheusルート:周辺の観測(Nginx/アプリ/ノード)と統合しやすい
入口のContract Testを運用に乗せたいなら、最終的には「テスト結果」だけでなく、
- Nginxのアクセスログの傾向
- upstreamの応答時間
- 502/504の増減
などの“周辺情報”も同じダッシュボードに並べられると、診断速度がさらに上がります。
ただし、最初からそこまで行くより、
- Artifacts保存
- 指標抽出(JSON化)
- 時系列DB
の順番が失敗しにくいです。
まとめ
Contract Testは、作るだけでは「赤い/緑」しか分かりません。
本当に効くのは、失敗時に 証拠が残る こと、そして性能劣化を 時系列で追える ことです。
- Playwrightは HTMLレポート + trace + screenshot(失敗時だけ) が鉄板
- k6は summary JSON を残すだけで比較が一気に楽になる
- CIでは 落ちてもArtifactsを必ずアップロード(always)
- メトリクス化は “まず抽出して保存” → “時系列DBへ” の段階設計が現実的
入口(Nginxやプロキシ設定)の変更はレビューが難しい領域だからこそ、アーティファクト化によって「説明できるテスト」にすると、運用の安心感が段違いになります。
コメントを残す