こんにちは。よっしーです(^^)
今日は、k6 の 複数のシナリオを利用したサンプル についてご紹介します。
背景
Dockerで構築したWebアプリの開発環境において、k6のExecutorsについて調査したときの内容を備忘として残しました。
開発環境のソースは下記のリポジトリにあります。
Externally controlled
- 異なる開始時刻を持つシナリオ: シナリオごとに異なる開始時刻を設定することで、ワークロードを順次実行できます。これにより、テストのトラフィックをより現実的にモデル化できます。
- シナリオごとのタグと環境変数: 各シナリオに異なるタグや環境変数を設定することで、それぞれのシナリオに固有の設定や情報を提供できます。これは、テスト内で異なる条件をシミュレートしたい場合に役立ちます。
- シナリオ固有の閾値: 各シナリオに対して異なる性能閾値を設定することで、シナリオごとに異なる品質基準を定義できます。これにより、特定のシナリオに対するパフォーマンスの評価を行うことができます。
- 異なるテストロジックを実行するための複数のシナリオ: 複数のシナリオを使用して、異なるテストロジックを実行できます。これにより、VUsがデフォルトの関数だけを実行しないようにし、多様なテストケースをカバーできます。
複数のシナリオを組み合わせることで、より複雑なテストシナリオを作成し、さまざまなテストケースを実行できます。これは、実世界のアプリケーションの挙動をより正確にモデル化し、性能や信頼性をテストするために役立ちます。
シナリオの組み合わせ
startTimeプロパティを使用すると、スクリプト内の一部のシナリオを他のシナリオよりも遅く開始するように設定できます。シナリオをシーケンスするために、startTimeを実行期間に関連付けたり、特定のエグゼキュータに固有のdurationオプションと組み合わせたりできます(特にarrival-rate executorsなどの実行期間が設定されているエグゼキュータと組み合わせると簡単です)。
このスクリプトでは、contactsとnewsという2つのシナリオが連続して実行されます:
- テストの開始時、k6はcontactsシナリオを開始します。50のVUが30秒間でできるだけ多くのイテレーションを実行しようとします。
- 30秒後、k6はnewsシナリオを開始します。50のVUがそれぞれ1分間で100回のイテレーションを実行しようとします。
startTime、duration、maxDurationとともに、各シナリオの異なるテストロジックに注目してください。これにより、異なるシナリオで異なる振る舞いをモデル化し、テストケースを作成できます。
import http from 'k6/http';
export const options = {
discardResponseBodies: true,
scenarios: {
contacts: {
executor: 'constant-vus',
exec: 'contacts',
vus: 50,
duration: '30s',
},
news: {
executor: 'per-vu-iterations',
exec: 'news',
vus: 50,
iterations: 100,
startTime: '30s',
maxDuration: '1m',
},
},
};
export function contacts() {
http.get('https://test.k6.io/contacts.php', {
tags: { my_custom_tag: 'contacts' },
});
}
export function news() {
http.get('https://test.k6.io/news.php', { tags: { my_custom_tag: 'news' } });
}
このスクリプトは、2つの異なるシナリオ contacts
と news
を持ち、それぞれが異なるエグゼキュータを使用してウェブリクエストを実行する例です。主なポイントは以下の通りです:
options
セクションで、シナリオごとに異なる設定を指定しています。例えば、contacts
シナリオではconstant-vus
エグゼキュータを使用し、news
シナリオではper-vu-iterations
エグゼキュータを使用しています。- 各シナリオ内の関数
contacts
とnews
は、HTTPリクエストを実行しています。各リクエストには、異なるタグ(tags
)が指定されており、メトリクスに追加のカスタムタグを付けることができます。これにより、メトリクスをより詳細に分析する際に役立ちます。 - シナリオごとに異なるテストロジックが実行され、
contacts
シナリオではウェブページhttps://test.k6.io/contacts.php
へのリクエストが、news
シナリオではウェブページhttps://test.k6.io/news.php
へのリクエストが実行されます。
このように、k6を使用すると、異なるシナリオごとに異なるエグゼキュータ、設定、テストロジック、タグを設定できます。これにより、さまざまなテストケースやシナリオを効果的に実行し、アプリケーションの性能評価を行うことができます。
異なる環境変数およびタグをシナリオごとに使用する
異なる環境変数およびタグをシナリオごとに使用することができます。前の例ではHTTPリクエストのメトリクスに個別のタグを設定しましたが、シナリオごとにタグを設定することもでき、これにより他のタグ可能なオブジェクトにも適用されます。
環境変数とタグをシナリオごとに設定することで、各シナリオに固有の設定や識別子を提供できます。これは、異なるシナリオが異なる条件で実行され、テスト結果を詳細に追跡および分析する際に非常に役立ちます。たとえば、異なるシナリオに対して異なるデータセットやテスト条件を設定する場合に使用できます。
import http from 'k6/http';
import { fail } from 'k6';
export const options = {
discardResponseBodies: true,
scenarios: {
contacts: {
executor: 'constant-vus',
exec: 'contacts',
vus: 50,
duration: '30s',
tags: { my_custom_tag: 'contacts' },
env: { MYVAR: 'contacts' },
},
news: {
executor: 'per-vu-iterations',
exec: 'news',
vus: 50,
iterations: 100,
startTime: '30s',
maxDuration: '1m',
tags: { my_custom_tag: 'news' },
env: { MYVAR: 'news' },
},
},
};
export function contacts() {
if (__ENV.MYVAR != 'contacts') fail();
http.get('https://test.k6.io/contacts.php');
}
export function news() {
if (__ENV.MYVAR != 'news') fail();
http.get('https://test.k6.io/news.php');
}
このスクリプトは、2つの異なるシナリオ contacts
と news
を持つ例です。それぞれのシナリオは異なるエグゼキュータを使用し、異なるテストロジックを実行します。
主なポイントは以下の通りです:
options
セクションで、シナリオごとに異なる設定を指定しています。例えば、contacts
シナリオではconstant-vus
エグゼキュータを使用し、news
シナリオではper-vu-iterations
エグゼキュータを使用しています。- シナリオごとに異なるタグ(
tags
)と環境変数(env
)も設定されています。これにより、メトリクスやテストロジックにシナリオ固有の情報を追加できます。 contacts
シナリオのcontacts
関数とnews
シナリオのnews
関数がそれぞれ異なるテストロジックを実行します。また、テストの前に環境変数MYVAR
を確認し、シナリオ固有の値に合致しない場合はfail()
を呼び出すことで、環境変数の一貫性を確認しています。
このように、k6を使用すると、異なるシナリオごとに異なるテスト条件、テストロジック、タグ、環境変数を設定できます。これにより、複数のシナリオを組み合わせてさまざまなテストケースを実行し、柔軟性のあるテストスイートを構築できます。
デフォルトでは、k6は各シナリオのすべてのメトリクスにシナリオ名を値とするシナリオタグを適用します。これらのタグを閾値と組み合わせたり、結果のフィルタリングを簡素化するために使用したりすることができます。
シナリオタグを無効にするには、–system-tagsオプションを使用します。シナリオタグを無効にすると、メトリクスにシナリオ関連のタグが適用されなくなります。
異なるシナリオ関数に異なる閾値を設定する
異なるシナリオ関数に異なる閾値を設定することもできます。これを行うには、以下の手順に従います:
- シナリオ固有のタグを設定します。
- これらのタグに対する閾値を設定します。
以下は、異なるexec関数、タグ、環境変数、および閾値を持つ3つのシナリオを持つテストの例です。各シナリオには異なる閾値が設定されています。
import http from 'k6/http';
import { sleep } from 'k6';
export const options = {
scenarios: {
my_web_test: {
// some arbitrary scenario name
executor: 'constant-vus',
vus: 50,
duration: '5m',
gracefulStop: '0s', // do not wait for iterations to finish in the end
tags: { test_type: 'website' }, // extra tags for the metrics generated by this scenario
exec: 'webtest', // the function this scenario will execute
},
my_api_test_1: {
executor: 'constant-arrival-rate',
rate: 90,
timeUnit: '1m', // 90 iterations per minute, i.e. 1.5 RPS
duration: '5m',
preAllocatedVUs: 10, // the size of the VU (i.e. worker) pool for this scenario
tags: { test_type: 'api' }, // different extra metric tags for this scenario
env: { MY_CROC_ID: '1' }, // and we can specify extra environment variables as well!
exec: 'apitest', // this scenario is executing different code than the one above!
},
my_api_test_2: {
executor: 'ramping-arrival-rate',
startTime: '30s', // the ramping API test starts a little later
startRate: 50,
timeUnit: '1s', // we start at 50 iterations per second
stages: [
{ target: 200, duration: '30s' }, // go from 50 to 200 iters/s in the first 30 seconds
{ target: 200, duration: '3m30s' }, // hold at 200 iters/s for 3.5 minutes
{ target: 0, duration: '30s' }, // ramp down back to 0 iters/s over the last 30 second
],
preAllocatedVUs: 50, // how large the initial pool of VUs would be
maxVUs: 100, // if the preAllocatedVUs are not enough, we can initialize more
tags: { test_type: 'api' }, // different extra metric tags for this scenario
env: { MY_CROC_ID: '2' }, // same function, different environment variables
exec: 'apitest', // same function as the scenario above, but with different env vars
},
},
discardResponseBodies: true,
thresholds: {
// we can set different thresholds for the different scenarios because
// of the extra metric tags we set!
'http_req_duration{test_type:api}': ['p(95)<250', 'p(99)<350'],
'http_req_duration{test_type:website}': ['p(99)<500'],
// we can reference the scenario names as well
'http_req_duration{scenario:my_api_test_2}': ['p(99)<300'],
},
};
export function webtest() {
http.get('https://test.k6.io/contacts.php');
sleep(Math.random() * 2);
}
export function apitest() {
http.get(`https://test-api.k6.io/public/crocodiles/${__ENV.MY_CROC_ID}/`);
// no need for sleep() here, the iteration pacing will be controlled by the
// arrival-rate executors above!
}
この例では、異なるシナリオ関数に対して異なる閾値を設定する方法が示されています。以下はこのスクリプトの主要なポイントです:
- スクリプトには3つのシナリオが定義されています。それぞれが異なるエグゼキュータ、タグ、環境変数、および閾値を持っています。
- 各シナリオは、ウェブテストとAPIテストを実行します。それぞれのテストロジックは関数
webtest
とapitest
によって実行されます。 - 各シナリオには異なる閾値が設定されており、
thresholds
セクションで閾値の条件が指定されています。これにより、異なるシナリオに対して異なる性能評価を設定できます。たとえば、APIテストとウェブテストに異なる閾値を設定しています。 - シナリオごとに異なるタグが設定されており、タグを使用して閾値を指定することができます。これにより、特定のシナリオに対して異なる閾値を適用できます。
- 各シナリオには環境変数も設定されており、環境変数を通じてシナリオごとに異なる設定を提供できます。
このように、k6を使用して異なるシナリオに対して異なる閾値を設定することができ、テストの柔軟性を向上させることができます。また、異なるテストロジックや条件を持つシナリオを組み合わせて、さまざまなテストケースを実行できます。
おわりに
今日は、k6 の 複数のシナリオを利用したサンプル についてご紹介しました。
何か質問や相談があれば、コメントをお願いします。また、エンジニア案件の相談にも随時対応していますので、お気軽にお問い合わせください。
それでは、また明日お会いしましょう(^^)
コメント