20 September 2019

使用k6进行GraphQL负载测试

Pepe Cano 著,Ng Wai Foong 译

在过去的几年里,GraphQL的普及和采用令人印象特别深刻, 而随着越来越多的用户开始发现 k6后,我们收到了很多关于GraphQL的问题。 这篇文章为那些刚刚开始使用k6的人提供了一些有用的提示和信息 ,以进行GraphQL负载测试。

k6是否支持测试GraphQL?

简单来说,k6是支持通过HTTPWebSocket进行GraphQL测试。

由于用户在使用GraphQL或k6的过程当中,我们发现很多用户对GraphQL和k6的使用存在一些疑惑,对此,我将进一步对以上的内容做详细解答。

GGraphQL是一种与传输层无关的"查询语言"

GraphQL是一种用于查询和操作API的语言;该规范定义了与GraphQL API通信的语法。

例如,基于以下API模式:

type Query {
me: User
}
type User {
id: ID
name: String
}

查询将是:

{
me {
name
}
}

GraphQL是与传输层无关的;它不限制GraphQL服务器通过特定的传输协议运行。HTTP是常见的选择,因为它的普遍性,但是GraphQL服务器可以在不同的协议上运行,例如:

  • 高级协议:HTTP,高级消息队列协议(AMQP),Websockets等。
  • 低级协议:传输控制协议(TCP),用户数据报协议(UDP),gRPC等。

在撰写本文时,k6等同于“GraphQL客户端” ,可以通过HTTPWebsocket生成请求,这意味着k6可以对任何k6所支持的协议运行,并且能用GraphQL服务器进行负载测试。

测试GitHub GraphQL API的示例

以下示例使用k6测试GraphQL服务,为了避免设置并运行我们自己的GraphQL服务器,我们将对GitHub GraphQL API进行负载测试,我们之所以选择GitHub API,是因为它对开发者来说很熟悉,文档齐全并且具有多种架构类型,查询和突变(mutations)。

首先,我们需要一个个人访问令牌(Personal Access Token)向GitHub API进行身份验证,按照本指南创建一个个人访问令牌来运行这个测试。根据我们测试的要求,您的令牌需要不同的权限或范围,对于下一个示例,您的令牌需要以下权限:

  • 访问公共存储库: repo:public_repo
  • 读写团队讨论: write:discussion
如何创建我的第一个GraphQL请求?

由于GitHub GraphQL API是通过HTTP运行的,而GraphQL的查询或突变需要一个JSON格式的请求体,您将使用http.post函数来生成调用API的请求。

我们可以通过从GitHub API获取一些数据来开始测试:

k6项目的第一个GitHub议题是哪个?

这道题的代码很简单;您只需要在授权标头上设置您的令牌,编写GraphQL查询(Object/Repository/Issues)并发送POST请求。

const accessToken = 'YOUR_GITHUB_ACCESS_TOKEN';
const query = `
query FindFirstIssue {
repository(owner:"grafana", name:"k6") {
issues(first:1) {
edges {
node {
id
number
title
}
}
}
}
}`;
const headers = {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json',
};
const res = http.post('https://api.github.com/graphql', JSON.stringify({ query: query }), {
headers: headers,
});

现在,我们的k6脚本只是调用端点来请求相同的数据,但我们想创建一个测试来复制一个特定的用户交互。

调试响应数据

在写脚本时,您应该检查响应内容以验证数据或在负载测试中使用它。

if (res.status === 200) {
console.log(JSON.stringify(res.body));
const body = JSON.parse(res.body);
const issue = body.data.repository.issues.edges[0].node;
console.log(issue.id, issue.number, issue.title);
}

输出结果如下:

INFO[0001] "{"data":{"repository":{"issues":{"edges":[{"node":{"id":"MDU6SXNzdWUxNzA0MzczOTY=","number":4,"title":"Deduplicate HTTP client code"}}]}}}}"
INFO[0001] MDU6SXNzdWUxNzA0MzczOTY= 0=4 1="Deduplicate HTTP client code"
运行一个突变以对第一个k6议题添上添加🎉反应

这个简单的示例旨在展示如何基于从另一个请求中获取的数据来更新服务器数据。在GraphQL中,您将使用突变来修改数据。

您可以阅读addReaction 档文或查找示例以了解此突变的语法。在这种情况下,addReaction突变需要issue.id来为议题添加🎉反应。

例子如下:

const mutation = `
mutation AddReactionToIssue {
addReaction(input:{subjectId:"${issue.id}",content:HOORAY}) {
reaction {
content
}
subject {
id
}
}
}`;
res = http.post('https://api.github.com/graphql', JSON.stringify({ query: mutation }), {
headers: headers,
});

现在,您可以运行测试,将鼠标悬停在🎉上,查看对k6议题的反应,查看完整的示例

easygraphql-load-tester

当我们发现到easygraphql-load-tester使用k6时,这真是令我们惊喜,发现用户在使用您的产品,尤其是以意想不到且有用的方式的情况下使用您的产品,这是令人鼓舞的,也是了解我们用户需求的好方法。

easygraphql-load-tester是个很有创意的主意,是一个使GraphQL负载测试尽可能简单的Node库。

const userSchema = fs.readFileSync(path.join(__dirname, 'schema', 'user.gql'), 'utf8');
const familySchema = fs.readFileSync(path.join(__dirname, 'schema', 'family.gql'), 'utf8');
const easyGraphQLLoadTester = new EasyGraphQLLoadTester([userSchema, familySchema]);
easyGraphQLLoadTester.k6('k6.js');
// or use
easyGraphQLLoadTester.artillery();

重用架构文件是一种智能且快速的方式,可以对GraphQL后端进行负载测试并运行,而无需编写任何GraphQL查询。此外,这个库让您可以选择使用artillery或者k6 😉来运行负载测试。

如果您想要一种快速方法来创建调用GraphQL查询的简单负载测试,我们认为easygraphql-load-tester在此方面非常好用。

这个库不限于根据架构查询自动生成负载测试。您可以自定义自己的载测试请求选择或生成自定义查询,以及使用突变。如果您想进一步了解更多关于这些功能,请参考官方文档

简单测试总比没有测试好

easygraphql-load-tester无法创建更真实的测试,比如其中一个请求需要前一个请求的一些信息。我们之前在以开发者为中心的宣言中也曾写过这个话题:简单测试总比没有测试好

单元负载测试就是单独测试一个单元,如API端点。

场景负载测试是为了测试真实世界的交互流程。

easygraphql-load-tester适合进行"单位负载"类型的测试,与其他许多测试工具一样,它无法创建真实世界的场景,比如:

  • 登录并获取用户令牌。
  • 使用令牌来列出您的项目。
  • 对项目进行操作。

我们提供了此类测试的k6示例,建议您使用k6进行这方面的测试。

结论

我们经常收到很多GraphQL相关的问题,比如:

我们试图在本文中澄清上面所提到的一些问题。总结一下,使用k6测试GraphQL就像生成带有数据的请求一样简单。

本文还包含了一个基本的例子,为使用k6测试GraphQL服务提供了一个起点,我们想把这篇文章写得简短一些,但可能性是无穷无尽的,k6脚本和k6选项(options)允许运行各种不同类型的性能测试。

< Back to all posts