将 Chai 与 k6 一起使用
随着代码库的增长,工程团队可能会采用一些框架或库来帮助他们编写更具可读性和可维护性的代码。同样,随着团队编写新的 k6 测试脚本或扩展现有测试,您可能会开始寻找方法来保持它们的可读性和组织性,以便将来更容易更新。
Chai 是一个 BDD/TDD 断言库,常用于测试框架。您可以通过使用 k6chaijs 库将 Chai 与 k6 一起使用。通过 k6chaijs,您可以获得
- BDD(行为驱动开发)风格的断言,语言更具表现力
- 可链式断言
- 更强大的断言函数,例如:
deep
,nested
,ordered
等。 - 自动断言消息
- 异常处理,以提高测试稳定性
您可以使用 k6chaijs 替代 check 和 group 函数。
安装
k6chaijs 库托管在 jslib 上,可以直接导入到您的 k6 脚本中。
import { describe, expect } from 'https://jslib.k6.io/k6chaijs/4.5.0.1/index.js';
或者,您可以使用本地存储的此文件副本。源代码可在 GitHub 上找到。
k6chaijs 的优势
以下是使用 k6chaijs 编写更优测试的一些方法。
表达性语言
使用 expect
和 describe
方法可以使代码更易于阅读和维护。例如,检查字符串长度是否等于五的代码片段如下所示
if ('Hello'.length !== 5) {
throw new Error(`Expected 'Hello' to have a length of 5 but got ${'Hello'.length}`);
}
使用 Chai,可以重写如下
import { describe, expect } from 'https://jslib.k6.io/k6chaijs/4.5.0.1/index.js';
describe('should match expected length', () => {
expect('Hello').to.have.lengthOf(5);
});
自动消息
Chai 还可以通过提供自动错误消息来帮助您的代码更加简洁。例如,执行以下代码会触发错误
import { describe, expect } from 'https://jslib.k6.io/k6chaijs/4.5.0.1/index.js';
describe('should match expected length', () => {
expect('Goodbye').to.have.lengthOf(6);
});
当您运行该代码时,您会自动收到一条错误消息,而无需编写任何额外代码,该消息为
// 🔥 AssertionError: expected 'Goodbye' to have a length of 6 but got 7
结构化测试
通过封装,您的测试可以为应用程序定义不同的部分。这使得以下变得更容易
- 定位测试。
- 发现缺失的边缘情况。
- 保持整洁。
- 提供用于添加额外测试的逻辑格式。
例如,您可以在测试脚本中封装针对两个不同服务的测试,如下所示
import { describe } from 'https://jslib.k6.io/k6chaijs/4.5.0.1/index.js';
describe('service A', () => {
describe('should do x from service A', () => {
/*...*/
});
describe('should do y from service A', () => {
/*...*/
});
});
describe('service B', () => {
describe('should do x from service B', () => {
/*...*/
});
describe('should do y from service B', () => {
/*...*/
});
});
断言 API 响应
断言库通常用于编写模拟单元/集成测试,但您也可以使用它来测试任何 API 响应。例如
import expect from 'https://jslib.k6.io/k6chaijs/4.5.0.1/index.js';
import http from 'k6/http';
const expected = { foo: 'Hello', bar: 'World' };
const response = http.get('https://your.example.domain');
expect(response.body).to.deep.equal(expected);
使用 describe
进行错误处理
check
函数无法保护您的测试免受不安全代码的影响。如果检查失败,k6 会抛出异常并从头开始重新启动脚本执行。例如
import { check } from 'k6';
import http from 'k6/http';
export default function () {
const response = http.get('https://your.example.domain'); // 🙈 could return Error 503
check(response, {
'got more than 5 items': (res) => {
// 🙉 `.json()` might be undefined
return res.json().length > 5;
},
}); // 🙊 k6 will throw an exception and restarts execution from the beginning.
// 💀 RIP
check(response, {
/*...*/
});
}
使用 k6chaijs,错误处理是自动提供的。脚本错误会被 describe 块捕获,并且执行可以继续到下一组测试。例如
import { describe, expect } from 'https://jslib.k6.io/k6chaijs/4.5.0.1/index.js';
import http from 'k6/http';
export default function () {
// 😇 You are safe now
describe('got more than 5 items', () => {
const response = http.get('https://your.example.domain'); // 🙈 could return Error 503
// 🙉 `.json()` might be undefined
expect(response.json()).to.have.lengthOf(5);
});
describe('hooray I still get a turn!', () => {
/*...*/
});
}
示例
以下脚本包含阈值和三个使用 Chai 的测试用例
- 一个
describe
函数创建部分并将测试分组。 - 另一个
describe
清晰地说明了我们希望从每个测试中实现的目标。 - Chai 的 BDD 风格
expect
函数用于以富有表现力、易于阅读的方式编写测试。
import { describe, expect } from 'https://jslib.k6.io/k6chaijs/4.5.0.1/index.js';
import http from 'k6/http';
export default function () {
const headers = { Authorization: 'token abcdef0123456789' };
describe('crocodiles API', () => {
describe('should fetch a list of public crocodiles', () => {
const response = http.get('https://quickpizza.grafana.com/api/ratings', { headers: headers });
expect(response.status, 'response status').to.equal(200);
expect(response).to.have.validJsonBody();
expect(response.json('ratings').length, 'number of ratings').to.be.above(1);
});
describe('should respond with status 200, when a valid rating id is provided', () => {
const expected = {
id: 1,
stars: 5,
pizza_id: 1,
};
const response = http.get('https://quickpizza.grafana.com/api/ratings/1', {
headers: headers,
});
expect(response.status, 'status').to.equal(200);
expect(JSON.parse(response.body), 'response body').to.deep.equal(expected);
});
describe('should respond with status 404, when an invalid rating id is provided', () => {
const response = http.get('https://quickpizza.grafana.com/api/ratings/12312123123123', {
headers: headers,
});
expect(response.status, 'status').to.equal(404);
expect(JSON.parse(response.body).error, 'error message').to.contain('not found');
});
});
}
k6 用户会使用 group
函数来执行此类操作,但是,对于 JavaScript 测试框架的用户来说,describe
是更熟悉的术语。在底层,k6chaijs 仍然调用 group
,但它封装了额外的逻辑。expect
函数也是如此。这可以帮助已经熟悉测试框架的用户,同时仍然提供与内置 k6 函数相同的输出摘要。