模块
导入模块
在您的测试脚本中导入模块或模块的部分内容是很常见的。在 k6 中,您可以导入不同类型的模块
内置模块
k6 提供了许多内置模块以实现核心功能。例如,http
客户端可向被测系统发起请求。有关内置模块的完整列表,请参阅API 文档。
import http from 'k6/http';
本地模块
这些模块存储在本地文件系统中,可通过相对或绝对文件系统路径访问。
k6 采用类似浏览器的模块解析,不支持Node.js 模块解析。import
的文件名必须完全指定,例如 ./helpers.js
。
//my-test.js
import { someHelper } from './helpers.js';
export default function () {
someHelper();
}
//helpers.js
export function someHelper() {
// ...
}
远程模块
这些模块通过 HTTP(S) 访问,来源可以是公共源,例如 GitHub、任何 CDN 或任何可公开访问的 Web 服务器。导入的模块在运行时下载并执行,因此,在将代码包含到测试脚本中之前,确保您信任该代码至关重要。
例如,jslib 是一组 k6 JavaScript 库,可用作远程 HTTPS 模块。您可以将其下载为本地模块导入,也可以直接将其作为远程模块导入。
import { randomItem } from 'https://jslib.k6.io/k6-utils/1.2.0/index.js';
export default function () {
randomItem([1, 2, 3]);
}
您还可以构建自定义 JavaScript 库并通过公共 Web 托管进行分发。例如,k6-jslib-aws 和 k6-rollup-example 将其模块作为 GitHub Release Assets 进行托管。
扩展模块
与k6 API 一样,您可以使用 Go 代码构建自定义模块,并将其公开为 JavaScript 模块。这些自定义的 Go-to-JS 模块称为 k6 扩展。
下面是导入来自 xk6-kubernetes 扩展的 k6/x/kubernetes
模块的示例。
import { Kubernetes } from 'k6/x/kubernetes';
const podSpec = {
apiVersion: 'v1',
kind: 'Pod',
metadata: { name: 'busybox', namespace: 'testns' },
spec: {
containers: [
{
name: 'busybox',
image: 'busybox',
command: ['sh', '-c', 'sleep 30'],
},
],
},
};
export default function () {
const kubernetes = new Kubernetes();
kubernetes.create(podSpec);
const pods = kubernetes.list('Pod', 'testns');
pods.map(function (pod) {
console.log(pod.metadata.name);
});
}
k6 扩展(Go-to-JS 模块)如何工作?为了增强性能,k6 引擎使用 Go 编写,并嵌入了一个 JavaScript VM (sobek) 来执行 JavaScript 测试代码。这使您可以使用 Go 代码构建自己的模块,并像往常一样将其作为 JavaScript 导入。
要了解有关使用或创建 k6 扩展的更多信息,请参阅扩展文档。
分享 JavaScript 模块
如前所述,用户可以通过加载本地或远程模块来导入自定义 JavaScript 库。因此,我们有两种导入 JavaScript 模块的选项,以及多种分发模块的方法。
注意
以下分发和共享 JavaScript 库的选项适用于自定义库和其他公共库。
远程模块
您可以将模块托管在公共 Web 服务器(如 GitHub 和任何 CDN)上,并进行远程导入。
// As GitHub release assets
import {
WorkloadConfig,
sayHello,
} from 'https://github.com/grafana/k6-rollup-example/releases/download/v0.0.2/index.js';
// or hosted in a CDN
import { randomIntBetween, randomItem } from 'https://jslib.k6.io/k6-utils/1.4.0/index.js';
当库包含多个文件和模块时,您可能希望将这些模块打包以创建公共版本。以下是一些参考示例
- 使用 Webpack:k6-jslib-utils 和 k6-jslib-aws。
- 使用 Rollup:test-commons。
请注意,k6 会自动执行远程模块,因此信任这些远程模块的源代码至关重要。**某些托管机制存在修改远程模块的风险**。为了减轻这种安全风险,一些用户更喜欢下载并在本地导入模块,以确保完全控制源代码。
本地模块
在此示例中,之前的远程模块已下载到测试项目的 lib
文件夹中,并按如下方式导入
import { WorkloadConfig, sayHello } from './libs/test-commons.js';
import { randomIntBetween, randomItem } from './libs/k6-utils.js';
分发库的另一种选项是使用 npm 等包管理器工具,它支持版本锁定和本地库的链接。后者在开发过程中非常有用。
虽然 k6 不解析 Node 模块,但您可以使用 Bundler 加载 npm 依赖项,如 k6-rollup-example 中所示。
使用 Node.js 模块
注意
k6 不是 Node.js 也不是浏览器。依赖 Node.js 提供的 API 的包,例如
os
和fs
模块,在 k6 中将无法工作。对于浏览器特定的 API,例如window
对象,也是如此。
在运行 Node.js 的 JavaScript 项目中,使用 import
或 require()
导入模块,并使用 Node.js 模块解析算法。这意味着用户可以按名称导入模块,而无需提供模块的完整文件系统路径。例如
import { ClassInAModule } from 'cool-module';
import
语句将由节点解析算法通过搜索以下位置自动解析
- 当前目录
- 目录中的任何
node_modules
文件夹 - 父目录中的任何
node_modules
文件夹,直到最接近的package.json
文件。
由于 k6 中的 import
实现不支持 Node 模块解析算法,因此需要将解析外部依赖项的 Node.js 模块转换为一个自包含、隔离的捆绑包。
这可以通过打包工具(例如 Webpack)的帮助来完成,Webpack 会分析测试脚本,识别所有外部依赖项,然后创建一个自包含的捆绑包,其中包含运行脚本所需的一切。
如果测试脚本没有外部依赖项,或者已经以与 k6 兼容的方式 vendored 了这些依赖项,或者只使用 ES5.1+ 功能,则无需使用打包工具。
选择打包工具
您可以使用任何支持转译的打包工具。流行的工具包括但不限于 webpack、parcel、rollup 和 browserify。
鉴于其灵活性、易用性、相对较低的资源消耗以及与 k6 的已知兼容性,推荐使用 webpack。
您还可以使用这两个示例仓库作为起点
- k6-template-es6: 使用 Webpack 和 Babel 在 k6 测试中启用 ES6 功能的模板。
- k6-rollup-example: 使用 Rollup 打包 k6 测试并发布共享库的示例。
Webpack 设置示例
从头开始设置 Babel 和 Webpack 项目可能听起来像一项艰巨的任务,但通常可以在几分钟内完成。首先创建一个项目文件夹并初始化 npm
mkdir ./example-project && \
cd "$_" && \
npm init -y
安装包
然后,安装所需的包
npm install --save-dev \
webpack \
webpack-cli \
@types/k6 \
babel-loader \
@babel/core \
@babel/preset-env \
core-js
包 | 使用方法 |
---|---|
webpack | Webpack 的打包器部分 |
webpack-cli | Webpack 的 CLI 部分,允许我们在终端中使用它 |
@types/k6 | k6 Typescript 定义 |
babel-loader | Webpack 在打包时利用 Babel 功能使用的加载器 |
@babel/core | Babel 的核心功能 |
@babel/preset-env | 一个智能预设,使用 browserlist、compat-table 和 electron-to-chromium 来确定需要转译和 polyfill 的代码。 |
core-js | 一个模块化的 JS 标准库,包含 polyfills |
配置 Webpack
添加这些包后,下一步是设置一个 webpack.config.js
文件
const path = require('path');
module.exports = {
mode: 'production',
entry: {
login: './src/login.test.js',
signup: './src/signup.test.js',
},
output: {
path: path.resolve(__dirname, 'dist'), // eslint-disable-line
libraryTarget: 'commonjs',
filename: '[name].bundle.js',
},
module: {
rules: [{ test: /\.js$/, use: 'babel-loader' }],
},
target: 'web',
externals: /k6(\/.*)?/,
};
模式
告诉 Webpack 自动使用与 mode
相关的优化。更多详情请参阅Webpack 文档。
入口
Webpack 在执行打包时将用作入口点的文件。从这些入口点开始,Webpack 将自动递归遍历所有导入,直到穷尽所有可能的依赖路径。例如
// login.test.js
import { SomeService } from './some.service.js';
const svc = new SomeService();
和
// some.service.js
import * as lodash from 'lodash';
export class SomeService {
constructor() {
this._ = lodash;
}
}
将导致 Webpack 打包 login.test.js
、some.service.js
以及 lodash
使用的所有上游依赖项。
输出
path
键接收一个绝对路径,打包完成的文件将放置在此处。在此示例中,使用 path.resolve
将 __dirname
和 'dist'
连接成一个绝对路径。
libraryTarget
键配置库的暴露方式。将其设置为 commonjs
将导致它使用 module.exports
导出。更多详情请参阅Webpack 文档。
顾名思义,filename
键配置完成的打包文件的名称。在此示例中,使用模板字符串 [name]
为输出文件名添加动态部分。
添加打包命令
打开 package.json
文件并添加一个新的脚本条目,用于运行打包过程。
{
"name": "bundling-example",
"description": "",
"version": "0.1.0",
"private": true,
"scripts": {
+ "bundle": "webpack"
}
...
}
打包测试
现在运行 Webpack 将输出两个不同的测试打包文件,它们可以独立执行
$ npm run bundle
# ...
$ tree dist
dist
├── login.bundle.js
└── signup.bundle.js
0 directories, 2 files
运行测试
$ npm run bundle
# ...
$ k6 run dist/login.bundle.js
# ...
$ npm run bundle
# ...
$ k6 run dist/signup.bundle.js \
--vus 10 \
--duration 10s
# ...
使用 TypeScript
k6 支持部分 TypeScript。有关更多详情,请参阅JavaScript 和 TypeScript 兼容模式。
将模块与 Docker 一起使用
在 Docker 容器中运行 k6(例如 Grafana k6 Docker 镜像)时,内置模块和远程模块即可直接使用。
本地模块
要使用 Docker 运行 k6 并导入本地模块,您必须使用 Docker 卷将宿主机的必要文件夹挂载到容器中。这样,k6 才能看到所有需要导入的 JS 模块。
例如,假设您的宿主机上具有以下结构
/home/k6/example/src/index.js
/home/k6/example/src/modules/module.js
import { hello_world } from './modules/module.js';
export default function () {
hello_world();
}
export function hello_world() {
console.log('Hello world');
}
要运行 index.js 并使模块可供导入,我们执行以下 Docker 命令,将 /home/k6/example/src
宿主机文件夹挂载到容器中的 /src
docker run --rm -v /home/k6/example/src:/src -i grafana/k6 run /src/index.js
请注意,在 Windows 上,您还需要确保相关驱动器(例如 C:\
)已在 Docker Desktop 设置中标记为共享。
扩展模块
官方的 Grafana k6 Docker 镜像包含 k6 发布二进制文件,但缺少额外的 k6 扩展。因此,使用官方 Docker 容器运行需要扩展的 k6 测试将会失败。
要在 Docker 中运行带有扩展的 k6,请创建一个包含带有您可能想使用的任何扩展的 k6 二进制文件的 Docker 镜像。定义一个包含必要的 xk6 构建指令的 Dockerfile
,如下所示
FROM grafana/xk6:latest
RUN GCO_ENABLED=0 xk6 build \
--with github.com/grafana/xk6-kubernetes@latest
ENTRYPOINT ["./k6"]
构建自定义 k6 Docker 镜像后,您可以像往常一样使用 Docker 运行 k6。
或者,您可以实现一个多阶段的 Dockerfile 构建,例如此Dockerfile 示例中所示。
阅读更多
- 组织 k6 性能测试套件的指南: 针对大型性能测试项目的建议。
- JavaScript 工具、共享库、多个仓库和中心团队: 构建性能测试项目并与其他团队共享 k6 库的选项。
- JSLib: 由 Grafana Labs 维护并可用作远程模块的 k6 JavaScript 库集合。
- 扩展目录: 由 Grafana Labs 和社区维护的 k6 扩展集合。
- k6-rollup-example: 使用 Rollup 和 Babel 打包常用库和测试套件的示例。
- k6-template-es6: 使用 Webpack 和 Babel 将 k6 测试打包到 CommonJS 模块并 polyfill ES+ 功能的模板。
- k6-template-typescript: 使用 Webpack 和 Babel 在 k6 脚本中使用 TypeScript 的模板。
- JavaScript 兼容模式: 一个更改 k6 支持的 ECMAScript 版本的选项。