k6 测试生命周期

Documentation
Grafana k6
Using k6
Test lifecycleOpen source

k6 测试生命周期

在k6测试的生命周期中,脚本始终按以下顺序经过各个阶段:

  1. init上下文中的代码准备脚本,包括加载文件、导入模块、定义生命周期函数。必需。
  2. setup函数设置测试环境并生成数据。可选。
  3. VU代码在default或场景函数中运行,持续时间与执行次数由选项决定。必需。
  4. 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()返回数据的一份独立副本。

Diagram showing data getting returned by setup, then used (separately) by default and teardown functions

在所有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);
    }

来源与许可

原文:Test lifecycle。本页为中文翻译与排版整理,示例源码保留原样,权利归原作者及维护者所有。

Copyright 2026 © Grafana Labs。官方版权声明。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容