Grafana k6
Using k6
Test lifecycleOpen source
k6 测试生命周期
在k6测试的生命周期中,脚本始终按以下顺序经过各个阶段:
init上下文中的代码准备脚本,包括加载文件、导入模块、定义生命周期函数。必需。setup函数设置测试环境并生成数据。可选。- VU代码在
default或场景函数中运行,持续时间与执行次数由选项决定。必需。 teardown函数进行数据后处理并关闭测试环境。可选。
注意
生命周期函数
除init代码外,每个阶段都对应一个生命周期函数,k6运行时会按特定顺序调用这些函数。
JavaScript
// 1. init code
export function setup() {
// 2. setup code
}
export default function (data) {
// 3. VU code
}
export function teardown(data) {
// 4. teardown code
}
生命周期阶段概览
各阶段的示例与实现细节见后续章节。
| 测试阶段 | 用途 | 示例 | 调用次数 |
|---|---|---|---|
| 1. init | 加载本地文件、导入模块、声明生命周期函数 | 打开JSON文件、导入模块 | 每个VU一次* |
| 2. Setup | 准备待处理数据,并在VU之间共享 | 调用API启动测试环境 | 一次 |
| 3. VU code | 运行测试函数,通常为default |
发送HTTPS请求、验证响应 | 每次迭代一次,按测试选项重复 |
| 4. Teardown | 处理setup代码的结果、停止测试环境 | 验证setup得到特定结果,发送Webhook通知测试结束 | 一次** |
* 在云端脚本中,init代码可能被调用更多次。
** 如果setup异常结束,例如抛出错误,则不会调用teardown()。应考虑在setup()中加入错误处理,以确保适当清理。
init 阶段
init阶段是必需的。测试运行前,k6需要初始化测试条件;为此,init上下文中的代码会对每个VU运行一次。
init阶段可以进行以下操作:
- 导入模块。
- 从本地文件系统加载文件。
- 配置测试选项。
- 定义VU、
setup和teardown阶段的生命周期函数,以及自定义函数或handleSummary()。
位于生命周期函数之外的全部代码,都属于init上下文,并且总是最先执行。
JavaScript
// init context: importing modules
import http from 'k6/http';
import { Trend } from 'k6/metrics';
// init context: define k6 options
export const options = {
vus: 10,
duration: '30s',
};
// init context: global variables
const customTrend = new Trend('oneCustomMetric');
// init context: define custom function
function myCustomFunction() {
// ...
}
把init与VU阶段分开,可以移除VU代码中与测试执行无关的计算,提高k6性能,让结果更可靠。init代码的一个限制是不能发送HTTP请求;由于协议请求的响应动态且不可预测,这一限制有助于保证init阶段在不同测试间可复现。
VU 阶段
脚本至少需要一个定义VU逻辑的场景函数,函数中的代码称为VU代码。通常它位于default函数中,也可以放在场景指定的函数里,示例见后文。
JavaScript
export default function () {
// do things here...
}
在测试持续期间,VU代码会反复执行。它可以发送HTTP请求、输出指标,以及完成通常期望负载测试完成的工作,但不包括属于init上下文的任务。
- VU代码不从本地文件系统加载文件。
- VU代码不导入其他模块。
这些任务应由init代码完成。
default 函数的生命周期
一个VU会从头到尾顺序执行default()。到达函数末尾后,回到开头并再次执行全部代码。
作为这一“重新开始”过程的一部分,k6会重置VU:清除Cookie,并且可能断开TCP连接,具体取决于测试配置。
setup 与 teardown 阶段
与default一样,setup和teardown必须是导出函数;区别在于每次测试中,k6只调用setup和teardown各一次。
setup在测试开始时调用,位于init之后、VU阶段之前。teardown在测试结束时调用,位于VU阶段(default函数)之后。
与init不同,setup和teardown可以调用完整的k6 API,例如发送HTTP请求:
JavaScript
import http from 'k6/http';
export function setup() {
const res = http.get('https://quickpizza.grafana.com/api/json');
return { data: res.json() };
}
export function teardown(data) {
console.log(JSON.stringify(data));
}
export default function (data) {
console.log(JSON.stringify(data));
}
setup()必须在配置的setupTimeout内完成,默认期限为60秒。超时后,测试会在任何VU启动前失败。
在Grafana Cloud k6中,setupTimeout最多为10分钟。如果setup()包含耗时操作,可考虑把重负载工作移到外部进程,再把结果传给测试。
跳过 setup 与 teardown
使用--no-setup和--no-teardown选项可以跳过相应阶段。
Bash
k6 run --no-setup --no-teardown ...
在 default 和 teardown 中使用 setup 数据
再来看一次k6测试的基本结构:
JavaScript
// 1. init code
export function setup() {
// 2. setup code
}
export default function (data) {
// 3. VU code
}
export function teardown(data) {
// 4. teardown code
}
default()和teardown()的函数签名接受一个参数,这里称为data。
以下示例把setup的数据传给VU和teardown阶段:
JavaScript
export function setup() {
return { v: 1 };
}
export default function (data) {
console.log(JSON.stringify(data));
}
export function teardown(data) {
if (data.v != 1) {
throw new Error('incorrect data: ' + JSON.stringify(data));
}
}
利用setup()返回的数据,可以:
- 让每个VU访问一份相同的数据副本。
- 在
teardown代码中进行数据后处理。
不过,也存在一些限制:
setup与其他阶段之间只能传递数据,也就是JSON,不能传递函数。setup()返回的数据较大时,会占用更多内存。- 不能在
default()中修改数据,再把修改后的数据传给teardown()。
可以把它理解为:每个阶段、每个VU,都会拿到setup()返回数据的一份独立副本。

在所有VU之间传递可变数据,最后再交给teardown,会非常复杂且计算成本高昂,尤其是在分布式环境中。这也违背了k6的一个核心目标:同一脚本应当能以多种模式执行。
其他生命周期函数
k6还提供以下生命周期函数用法:
-
handleSummary():如果需要自定义汇总,k6会在测试最末尾额外调用这一生命周期函数。
详情参见Custom summary。
-
场景函数:除了
default,也可以在场景函数中执行VU代码。JavaScript
import http from 'k6/http'; import { sleep } from 'k6'; export const options = { scenarios: { my_web_test: { // the function this scenario will execute exec: 'webtest', executor: 'constant-vus', vus: 50, duration: '1m', }, }, }; export function webtest() { http.get('https://test.k6.io/contacts.php'); sleep(Math.random() * 2); }











暂无评论内容