菜单
开源

模块

导入模块

在您的测试脚本中导入模块或模块的部分内容是很常见的。在 k6 中,您可以导入不同类型的模块

内置模块

k6 提供了许多内置模块以实现核心功能。例如,http 客户端可向被测系统发起请求。有关内置模块的完整列表,请参阅API 文档

JavaScript
import http from 'k6/http';

本地模块

这些模块存储在本地文件系统中,可通过相对或绝对文件系统路径访问。

k6 采用类似浏览器的模块解析,不支持Node.js 模块解析import 的文件名必须完全指定,例如 ./helpers.js

JavaScript
//my-test.js
import { someHelper } from './helpers.js';

export default function () {
  someHelper();
}
JavaScript
//helpers.js
export function someHelper() {
  // ...
}

远程模块

这些模块通过 HTTP(S) 访问,来源可以是公共源,例如 GitHub、任何 CDN 或任何可公开访问的 Web 服务器。导入的模块在运行时下载并执行,因此,在将代码包含到测试脚本中之前,确保您信任该代码至关重要。

例如,jslib 是一组 k6 JavaScript 库,可用作远程 HTTPS 模块。您可以将其下载为本地模块导入,也可以直接将其作为远程模块导入。

JavaScript
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-awsk6-rollup-example 将其模块作为 GitHub Release Assets 进行托管。

扩展模块

k6 API 一样,您可以使用 Go 代码构建自定义模块,并将其公开为 JavaScript 模块。这些自定义的 Go-to-JS 模块称为 k6 扩展

下面是导入来自 xk6-kubernetes 扩展的 k6/x/kubernetes 模块的示例。

JavaScript
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)上,并进行远程导入。

JavaScript
// 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';

当库包含多个文件和模块时,您可能希望将这些模块打包以创建公共版本。以下是一些参考示例

请注意,k6 会自动执行远程模块,因此信任这些远程模块的源代码至关重要。**某些托管机制存在修改远程模块的风险**。为了减轻这种安全风险,一些用户更喜欢下载并在本地导入模块,以确保完全控制源代码。

本地模块

在此示例中,之前的远程模块已下载到测试项目的 lib 文件夹中,并按如下方式导入

JavaScript
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 的包,例如 osfs 模块,在 k6 中将无法工作。对于浏览器特定的 API,例如 window 对象,也是如此。

在运行 Node.js 的 JavaScript 项目中,使用 importrequire() 导入模块,并使用 Node.js 模块解析算法。这意味着用户可以按名称导入模块,而无需提供模块的完整文件系统路径。例如

JavaScript
import { ClassInAModule } from 'cool-module';

import 语句将由节点解析算法通过搜索以下位置自动解析

  • 当前目录
  • 目录中的任何 node_modules 文件夹
  • 父目录中的任何 node_modules 文件夹,直到最接近的 package.json 文件。

由于 k6 中的 import 实现不支持 Node 模块解析算法,因此需要将解析外部依赖项的 Node.js 模块转换为一个自包含、隔离的捆绑包。

这可以通过打包工具(例如 Webpack)的帮助来完成,Webpack 会分析测试脚本,识别所有外部依赖项,然后创建一个自包含的捆绑包,其中包含运行脚本所需的一切。

如果测试脚本没有外部依赖项,或者已经以与 k6 兼容的方式 vendored 了这些依赖项,或者只使用 ES5.1+ 功能,则无需使用打包工具。

选择打包工具

您可以使用任何支持转译的打包工具。流行的工具包括但不限于 webpackparcelrollupbrowserify

鉴于其灵活性、易用性、相对较低的资源消耗以及与 k6 的已知兼容性,推荐使用 webpack

您还可以使用这两个示例仓库作为起点

  • k6-template-es6: 使用 Webpack 和 Babel 在 k6 测试中启用 ES6 功能的模板。
  • k6-rollup-example: 使用 Rollup 打包 k6 测试并发布共享库的示例。

Webpack 设置示例

从头开始设置 Babel 和 Webpack 项目可能听起来像一项艰巨的任务,但通常可以在几分钟内完成。首先创建一个项目文件夹并初始化 npm

bash
mkdir ./example-project && \
    cd "$_" && \
    npm init -y

安装包

然后,安装所需的包

bash
npm install --save-dev \
    webpack \
    webpack-cli \
    @types/k6 \
    babel-loader \
    @babel/core \
    @babel/preset-env \
    core-js
使用方法
webpackWebpack 的打包器部分
webpack-cliWebpack 的 CLI 部分,允许我们在终端中使用它
@types/k6k6 Typescript 定义
babel-loaderWebpack 在打包时利用 Babel 功能使用的加载器
@babel/coreBabel 的核心功能
@babel/preset-env一个智能预设,使用 browserlistcompat-tableelectron-to-chromium 来确定需要转译和 polyfill 的代码。
core-js一个模块化的 JS 标准库,包含 polyfills

配置 Webpack

添加这些包后,下一步是设置一个 webpack.config.js 文件

JavaScript
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 将自动递归遍历所有导入,直到穷尽所有可能的依赖路径。例如

JavaScript
// login.test.js

import { SomeService } from './some.service.js';

const svc = new SomeService();

JavaScript
// some.service.js

import * as lodash from 'lodash';

export class SomeService {
  constructor() {
    this._ = lodash;
  }
}

将导致 Webpack 打包 login.test.jssome.service.js 以及 lodash 使用的所有上游依赖项。

输出

path 键接收一个绝对路径,打包完成的文件将放置在此处。在此示例中,使用 path.resolve__dirname'dist' 连接成一个绝对路径。

libraryTarget 键配置库的暴露方式。将其设置为 commonjs 将导致它使用 module.exports 导出。更多详情请参阅Webpack 文档

顾名思义,filename 键配置完成的打包文件的名称。在此示例中,使用模板字符串 [name] 为输出文件名添加动态部分。

添加打包命令

打开 package.json 文件并添加一个新的脚本条目,用于运行打包过程。

diff
{
  "name": "bundling-example",
  "description": "",
  "version": "0.1.0",
  "private": true,
  "scripts": {
+    "bundle": "webpack"
  }
  ...
}

打包测试

现在运行 Webpack 将输出两个不同的测试打包文件,它们可以独立执行

bash
$ npm run bundle
# ...
$ tree dist

dist
├── login.bundle.js
└── signup.bundle.js

0 directories, 2 files

运行测试

bash
$ npm run bundle
# ...
$ k6 run dist/login.bundle.js
# ...
bash
$ 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
JavaScript
import { hello_world } from './modules/module.js';

export default function () {
  hello_world();
}
JavaScript
export function hello_world() {
  console.log('Hello world');
}

要运行 index.js 并使模块可供导入,我们执行以下 Docker 命令,将 /home/k6/example/src 宿主机文件夹挂载到容器中的 /src

bash
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,如下所示

bash
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 示例中所示。

阅读更多