はじめに
bravesoft株式会社でエンジニアをしているはっしーです。
今回新規受託案件にて負荷試験の実施をするにあたってCursor+k6を使った負荷試験の環境構築から簡単なテストスクリプトを用意したところまでを記事にしてみました
k6とは
Go言語で開発されたオープンソースの高性能な負荷試験ツールです。
テストシナリオをJavaScript(またはTypeScript)で記述し、アプリケーションのパフォーマンス、信頼性、耐久性をテストするために使用されています。
テストシナリオはJavaScriptまたはTypeScriptで記述します。これにより、Web開発者が使い慣れた言語で複雑なテストロジックを簡単に構築できます。
環境構築していこう
Cursorに色々と指示しながらまずは環境を構築していきましょう
- Docker
- k6
- Cursor
- k6にて負荷試験を行える環境を構築したい
- Node.jsプロジェクトとして初期化し、k6、@types/k6、typescript、biomeを開発依存パッケージとしてインストールするための**package.json**を作成してください
- k6のTypeScriptスクリプトをコンパイルするための**tsconfig.jsonを作成してください
- endPointは簡単に切り替えられるようenvに定義しておきたい
- docker+Kubernetes環境でk6が実行できるようにしてほしい
- node_modulesはgitignoreして
- READMEを用意して
など
記事用のサンプルなので指示が大雑把な指示になってますが実際は案件によって細かく指示出す方がいいでしょう
こんな感じでシンプルな環境が用意できました
簡単なテストスクリプトを実行してみる
1.簡単なここではお知らせリストを取得して既読にするような簡単なテストを書く
import { check, sleep } from 'k6';
// Notice list API test script (standalone version)
// For integrated tests, use integrated-test.ts instead
import http from 'k6/http';
import { API_CONFIG } from '../config.js';
// --- マスク処理のヘルパー関数を定義 ---
/**
* 文字列の最初と最後を残し、中間をアスタリスクでマスクします。
* @param str マスク対象の文字列
* @returns マスクされた文字列
*/
const maskString = (str: string, visibleLength = 4) => {
if (!str || str.length <= visibleLength * 2) {
return '***MASKED***';
}
const start = str.substring(0, visibleLength);
const end = str.substring(str.length - visibleLength);
return `${start}**********${end}`;
};
// ------------------------------------
// Test configuration
export const options = {
vus: 1,
iterations: 1,
duration: '1s',
};
// Test function
export default function () {
const appToken = API_CONFIG.appToken;
const maskedAppToken = maskString(appToken || '');
// Create headers with authorization
const headers = {
...API_CONFIG.headers,
'Authorization': `Bearer ${appToken}`,
'XXXXX': '',
'YYYYY': '',
};
// Query parameters
const page = __ENV.NOTICE_PAGE || '1';
const type = __ENV.NOTICE_TYPE || 'game';
// Build query string manually (k6 doesn't have URLSearchParams)
const queryString = `page=${page}&type=${type}`;
const url = `${API_CONFIG.baseUrl}/v1/notice/list?${queryString}`;
const maskedUrlPath = `/v1/notice/list?${queryString}`;
console.log(`Making request to: ${API_CONFIG.baseUrl} [Path: ${maskedUrlPath}]`);
const response = http.get(url, { headers });
const success = check(response, {
'status is 200': (r) => r.status === 200,
'response time < 2000ms': (r) => r.timings.duration < 2000,
'response has data': (r) => {
try {
const body = JSON.parse(r.body as string);
return body.result !== undefined || body.data !== undefined;
} catch {
return false;
}
},
});
if (success) {
console.log('✅ Notice list API test passed');
console.log(`Using Token: ${maskedAppToken}`);
try {
const body = JSON.parse(response.body as string);
console.log(
`Response: ${JSON.stringify(body, null, 2).substring(0, 500)}...`
);
} catch (e) {
console.log(`Response: ${response.body}`);
}
} else {
console.error('❌ Notice list API test failed');
console.error(`Status: ${response.status}`);
console.error(`Response: ${response.body}`);
console.error(`Attempted Token: ${maskedAppToken}`);
}
sleep(1);
}
2.作成したスクリプトをk6で実行してみる
$ cd xxxxxxx_k6 && export $(cat .env.local | grep -v '^#' | grep -v '^$' | xargs) && APP_TOKEN=XXXXXXX k6 run dist/test/notice-read-test.ts 2>&1
3.実行結果を確認してみる
こんな感じで結果が出力されるので結果を共有しやすい
お知らせリスト取得: 成功
7件のお知らせを取得
ページ1で全件取得
お知らせ既読: 成功
7件すべての既読に成功
すべてのリクエストが200 OK
パフォーマンス
リクエスト数: 9件(リスト取得2件 + 既読7件)
平均レスポンス時間: 79.97ms
エラー率: 0%
すべてのチェック: 100%成功
📊 k6の主な指標
| 指標名 | 内容 |
|---|---|
| checks | チェック関数の成功割合 |
| http_req_duration | HTTPリクエストの完了にかかった合計時間 |
| http_req_failed | 失敗したHTTPリクエストの割合 |
| iteration_duration | 1回のイテレーションを完了するのにかかった時間 |
| vus | アクティブな仮想ユーザー (VU) の数 |
| vus_max | 最大仮想ユーザー (VU) 数 |
| http_reqs | テスト中に生成されたHTTPリクエストの総数 |
| http_req_blocked | リクエスト開始前にブロックされている時間 |
| http_req_connecting | TCP接続の確立にかかった時間 |
シナリオ作成について
- OpenAPIの仕様書をCursorに渡す
- 対象のAPIのリストとテスト条件などをプロンプトに渡して各テストのスクリプトのベースを用意してもらう
- 閾値の調整や、条件などの細かい調整
繰り返し指示を与えていくことでAIがよしなに作成してくれますが、意図する通りに動かないこともあるので必要に応じて開発者が閾値の調整やスクリプトを調整していくことは必要です
結果の可視化について
負荷試験の結果はメトリクスとして Prometheus に送りだすことで、Grafana ダッシュボードで可視化することができます。 他にも、New Relic や Datadog 等、SaaS ツールとの連携も可能です。
今回はそこまでやりませんがk6-reporterで一旦可視化してみました。
テストスクリプトに以下の関数を追加することで、テスト実行後に自動的にHTMLレポートが生成されます
// @ts-ignore - k6-reporterはCDNから読み込むため型定義がない
import { htmlReport } from 'https://raw.githubusercontent.com/benc-uk/k6-reporter/main/dist/bundle.js';
// HTMLレポートを生成(k6-reporterを使用)
export function handleSummary(data: unknown) {
return {
'results/summary.html': htmlReport(data),
};
}
今後やりたいこと
- Grafana ダッシュボードで負荷試験の結果の可視化
- Cursorで基盤を作成できたので、量産はClaudCode MCPサーバーに情報を渡してテストに関する情報を渡して自動でテストスクリプトを作成してもらう
- kubernetesで分散して負荷試験をできるようにする
- 非エンジニア、QAメンバーでもテストスクリプトを組んでローカルでkubernetes + docker + k6実行できるようにする
まとめ
Cursorを効果的に活用し、k6による高性能な負荷試験環境を迅速に構築する手法を紹介しました。
このアプローチにより、開発初期段階からCI/CDに組み込む負荷試験環境を、エンジニアの作業コストを抑えつつ用意することが可能となると思います。
Grafanaでの可視化とLLMによるスクリプト自動生成は、負荷試験の質と効率を飛躍的に向上させる鍵となると思うので今後運用しながら色々と改善していければと思います。
bravesoftではエンジニアを募集しております。採用ページをご確認ください


