【AICon】AI 基础设施、LLM运维、大模型训练与推理,一场会议,全方位涵盖! >>> 了解详情
写点什么

手把手教你编写 HTTP 文件测试 HTTP API

  • 2020-06-09
  • 本文字数:7426 字

    阅读完需:约 24 分钟

手把手教你编写HTTP文件测试HTTP API


本文最初发布于 Renato Athaydes 的个人网站,经原作者授权由 InfoQ 中文站翻译并分享。


目前,为 HTTP API 编写自动化测试实在有点太复杂了。一般来说,你可以通过两种方法来解决这个问题:


  • 使用一个 HTTP 客户端用你喜欢的编程语言编写测试。

  • 使用 Postman、Swagger Inspector 和老一些的 SoapUI 等 GUI 工具。


我认为这些方法都不够理想。进一步来说,我认为这里有另一种解决方案,它在大多数情况下都好用得多,但知道的人却很少:那就是直接在一个文本文件中编写 HTTP,同时添加一些人性化的便利内容,带来更愉快的测试体验。


在这篇文章中,我会阐述当前方法中存在哪些问题,以及为什么 HTTP 文件是一个很好的替代方案。

编写 HTTP API 测试时面临的问题

用你喜欢的编程语言编写测试时,你有无限的灵活性。基本上,你想到什么就能做什么,因此就灵活性而言,程序化测试绝对是最佳选择。


但这同时也是程序化测试的问题所在:由于它们太通用了,因此代码很难阅读和维护。如果测试足够复杂,甚至连程序要测试的是什么东西都很难搞清楚。


这是很常见的状况,而且往往会带来一个问题:测试程序本身由谁来测试呢?你能保证测试失败是由 API 中的错误引起的吗?如果失败是因为测试程序中的错误引起的呢?


程序化测试也很难编写。由于某些原因,大多数语言的 HTTP 客户端都比较笨拙,难以使用。举个简单的例子,下面是大多数 Java 开发人员都必须处理的事情:


class GitHubUser {     private String login;     // standard getters and setters}
public class MyTest { @Test public void givenUserExists_whenUserInformationIsRetrieved_thenRetrievedResourceIsCorrect() throws ClientProtocolException, IOException { // Given HttpUriRequest request = new HttpGet( "https://api.github.com/users/eugenp" ); // When HttpResponse response = HttpClientBuilder.create().build().execute( request ); // Then GitHubUser resource = RetrieveUtil.retrieveResourceFromResponse( response, GitHubUser.class); assertThat( "eugenp", Matchers.is( resource.getLogin() ) ); }
public static <T> T retrieveResourceFromResponse(HttpResponse response, Class<T> clazz) throws IOException { String jsonFromResponse = EntityUtils.toString(response.getEntity()); ObjectMapper mapper = new ObjectMapper() .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); return mapper.readValue(jsonFromResponse, clazz); }
}
复制代码


上面的例子来自Baeldung网站


也许你认为这看起来还行,但我可不这么认为。我希望后文的分析能让你明白其实还有好得多的方法。

基于 GUI 的测试工具

基于 GUI 的测试工具所面临的问题大都与程序化测试相反:相比后者的高度灵活性而言,前者的限制太多,只能执行工具作者认为用户需要的那些功能。


他们总是尝试从用户那里抽象出“困难”的概念,因此在编写请求时,你可能会有一张带有许多“参数”的小桌子。这些是查询参数吗?还是表单参数?也许它们实际上是 JSON 主体的一部分?如果有人在测试你的 HTTP API,但无法分辨出它们之间的区别,那么你可能应该思考一下,他们要做的测试是不是那么可靠了。


这些工具通常都支持“脚本”来克服它们的某些局限,但如果你用了太多脚本,结果可能会同时陷进两个坑里:抽象一大堆,同时难以理解的代码也数不清,这些代码指不定会做什么事情。


基于 GUI 的工具还有一个缺陷,那就是它们很难与 CI 管道集成,并且在大多数情况下,一旦你想以这种方式使用它们就得掏钱了(或者你只需要一两项高级功能也得升级到专业版)。


鉴于此,我认为它们非常适合探索性测试,但不适用于在 CI 中运行的自动化测试(或作为开发人员常用测试套件的一部分)。

替代方案:HTTP 文件

本质上,HTTP 文件是一个文件,你可以在其中手工编写 HTTP 请求,使用一些小的代码段对运行请求时收到的响应做出断言,并在同一文件中设置可由后续请求使用的变量。


有两种非常相似但并不相同的 HTTP 文件格式:



它们都允许开发人员编写 HTTP 请求,并加入诸如自动完成、输入时高亮显示错误,以及在已知内容类型时使用颜色高亮显示 HTTP 响应正文之类的细节。


你可以把它看作是在你喜欢的 IDE 中编写 HTTP“代码”。



顺便说一句:HTTP最初被设计为用作分布式对象系统的一个接口。它易于理解,在不需要任何高级工具帮助的情况下也能手工编写。


如果你以前没有看过 HTTP 文件,请参考 VS Code REST Client 文档中的一个小示例:


GET https://example.com/comments/1 HTTP/1.1
###
GET https://example.com/topics/1 HTTP/1.1
###
POST https://example.com/comments HTTP/1.1content-type: application/json
{ "name": "sample", "time": "Wed, 21 Oct 2015 18:27:50 GMT"}
复制代码


这非常简单。只要你稍微了解一点 HTTP(如果你正在测试 HTTP API,那你肯定没问题),就会知道这是在做什么。最大的好处是:这些代码可以在 VS Code Editor 和 IntelliJ IDEA Ultimate(以及终端或 CI,后文详解)中运行,因为它们的格式非常相似!


再对比一下基于 GUI 的工具,在 GUI 工具中,你对 HTTP 的了解几乎毫无用处,因为你必须学习另一种事物才行:



不幸的是,Jetbrains 尚未在社区(免费)版本中提供 HTTP 文件支持,但希望在 VS Code 的竞争推动下,他们会在未来某个时候补上这个功能(我不知道他们是否有这个计划,只是希望他们能做到)!


VS Code REST Client 格式比 Jetbrains 格式的功能更多一些,但截至本文撰写时,只有 Jetbrains 格式支持测试。Jetbrains 格式的另一项优势是,它有一个名为HTTP Request in Editor的规范,我认为这是一个很棒的起点。将来这一规范可以用作通用 HTTP 测试格式的基础,真是激动人心。


因此我将重点介绍 Jetbrains HTTP 文件格式,用来说明我们该如何将 HTTP 文件用于测试。

使用 Request-in-Editor 格式测试 HTTP API

我想明确一点,我与 Jetbrains 没有任何利益关系,推广它的产品也不会获得任何商业利益。我与 Jetbrains 的唯一关系是我的雇主为所有开发人员(包括我自己)支付 IDEA 许可证的费用,因此我可能被视为“间接客户”。


我认为 Request-in-Editor 格式(它的确应该改个顺口的名字)确实是一种非常适合测试 HTTP API 的东西。


首先,它使用了HTTP RFC本身描述的基本 HTTP 消息格式,但额外添加了一些内容,使其更易于手工编写。


例如,一个简单的 HTTP 请求能用一个简单的 URL 表示:


http://date.jsontest.com/
复制代码


运行此文件会对该 URL 发出单个 GET 请求。你在这里需要知道的是:


  • 如果省略方法指定,则 GET 是默认方法。

  • 如果省略协议版本,则 HTTP/1.1 是默认协议版本。

  • 从 URL 推断出必需的 Host 标头。


因此,通过网络发送的完整 HTTP 请求如下所示:


GET / HTTP/1.1Host: date.jsontest.com
复制代码


请注意,URL scheme http 不属于请求本身,因为它仅建立传输协议;并且由于 HTTP 的历史原因,CRLF 被用作换行符。


我不知道,为什么程序化 HTTP 客户端和 GUI 测试工具对测试人员太难处理了,并试图将其抽象化。对我来说,“真实的东西”看起来更顺眼一些。


作为测试的示例,让我们在 HTTP 文件中实现前文的 Java 示例中所示的测试:


GET https://api.github.com/users/eugenpAccept: application/vnd.github.v3+jsonUser-Agent: renatoathaydes
> {%client.test('Given User Exists, ' + 'When User Information Is Retrieved, ' + 'Then Retrieved Resource Is Correct', function() { client.assert(response.body.login === 'eugenp'); });%}
复制代码


就该这么简单。


请注意,原始的 Java 示例实际上并未设置AcceptUser-Agent标头。上面的示例这样做是因为 GitHub 建议对所有请求都这样做(并且User-Agent现在是必需的)。


这个示例中有一些值得注意的细节:


  • 在 HTTP 请求后立即在<{%%}标记之间编写用于测试响应的代码。

  • 确切地说,代码是用 JavaScript,ECMAScript5.1 编写的。

  • 有一些内置函数可用于测试。

  • 由于响应的内容类型,request.body会自动解析为 JSON。


可在这些代码段中使用的 JavaScript API 都列在了在IntelliJ文档中,并且在 IntelliJ IDEA Ultimate 中编写代码时也可以内联显示(对于 Jetbrains 官方的呼吁:请在社区版中提供此功能!!这不是什么“企业级”功能!),并带有自动补全。


这种格式的另一项重要特性是,你能使用变量并在响应句柄脚本和环境文件中指定它们,这些文件是用 JSON 编写的。


例如,你可以创建环境文件,这些文件必须称为http-client.env.jsonhttp-client.private.env.json(以保留机密数据),如下所示:


{    "development": {        "host": "localhost",        "id-value": 12345,        "username": "joe",        "password": "123",        "my-var": "my-dev-value"    },
"production": { "host": "example.com", "id-value": 6789, "username": "bob", "password": "345", "my-var": "my-prod-value" }}
复制代码


现在,你可以在 HTTP 文件中使用变量了:


GET http://{{host}}/api/json/get?id={{id-value}}Authorization: Basic {{username}} {{password}}Content-Type: application/json
{"key": {{my-var}}}
复制代码


你还可以使用 JavaScript 设置变量:


client.globals.set('my-var', 100);
复制代码

运行 Request-in-Editor 文件

显然,以 Request-in-Editor 格式运行 HTTP 文件的最简单方法是在 IntelliJ IDEA Ultimate 中运行。


运行时,它看起来就像是在 IDE 中运行单元测试一样:



不幸的是,Jetbrains 似乎没有制作一个独立的可执行文件来运行此类文件……但是我认为这种格式确实很酷,应该有一个可以让任何人以最小开销运行的 runner 实现,帮助你编写更好的 HTTP。即便你没有许可证,API 也会在命令行或 CI 中测试并执行它们。


因此,我编写了一个 HTTP 文件 runner 作为一个 Java 库,这是我自己的RawHTTP 项目(称为rawhttp-req-in-edit的一部分。


我还向RawHTTP CLI添加了 run 命令,这样你就可以执行能在 IntelliJ 中运行的任何 HTTP 文件。


现在要运行 HTTP 文件时,只需从终端运行以下命令:


rawhttp run my.http
复制代码


如果要指定环境,请使用-e 选项传递其名称:


rawhttp run my.http -e development
复制代码


这些代码都是开源的,并在 Apache2.0 许可下发布!


我希望这有助于 HTTP 文件的普及,并希望这种方法能在业内流行开来,因为俗话说:我们应该使用合适的工具来完成工作!在我看来,HTTP 文件应该是完成这一重要任务的最佳工具。

HTTP 文件的缺点

尽管 HTTP 文件很棒,但我认为仍然需要解决一些问题才能让它们变得更好。

JavaScript 响应处理程序

对于这种小型脚本来说,JS 并不是一个糟糕的选项,但如果能有其他方法就更好了。


考虑到 Java 支持运行多种语言,这一缺陷应该很容易解决。


如果有兴趣,我可能会在自己的 runner 实现中添加对其他语言的支持。如果你有兴趣,请创建一个GitHub问题


另一方面,Jetbrains 之所以为此使用了过时的 ECMA 版本,似乎只是因为他们受到了限制。我的猜测是,他们正在使用已过时的 Nashorn 引擎来运行 JS 代码。在更现代的引擎中(例如 GraalVM 的 Polyglot 框架),使用现代 JavaScript 和其他语言应该是非常容易的。

缺乏声明性断言

就像用 HTTP 编写 HTTP 比用其他任何一种编程语言编写 HTTP 都更顺手一样,用 HTTP 特定的断言语言编写声明性断言可能也比用 JS 代码来写更合适一些。


例如,我一直希望能够编写如下内容:


GET /resources/id-1Host: mywebsite.com
### Expected ResponseHTTP/1.1 200 .*Content-Type: application/jsonContent-Length: > 20
{{ body.id == 'id-1' ... }}
复制代码


如果能编写这样的测试就太好了!我们只需要一种易于编写和理解的,在大多数情况下足够灵活,特定于 HTTP 的模式语言……就算它有什么缺陷,我们仍然可以回退到脚本上。


不过,我实在没时间和精力做这种事情了,如果有人有意愿的话请随时与我联系!我可能会提出一些想法并提供一些帮助!

实现中的错误

IntelliJ 对 HTTP 文件的支持似乎还是 Beta 阶段一样……其中有一些明显的错误,当你开始编写更高级的文件时可能就会遇到它们。


希望随着这种格式的流行,官方会付出更多的努力来更好地支持它。

结论

我们测试 HTTP API 的方式应该比现在常用的方法更简单一些,我希望这篇文章至少能让一些人相信 HTTP 文件是一个好主意。


我希望本文能引起大家的兴趣,推动业界对此类文件制定标准,并在将来让 VS Code、IntelliJ IDEA 和其他工具都汇聚为一种格式,因为这将让所有人受益。


最后,虽然现在的情况还不够理想,但你也可以同时使用 VS Code 和 IntelliJ 编写 HTTP 文件,并且如果需要,可以使用 RawHTTP 的 Java 库或其 CLI 在 CI 中运行 HTTP 文件。


英文原文:


Writing HTTP files to test HTTP APIs


2020-06-09 15:483574
用户头像
王强 技术是文明进步的力量

发布了 789 篇内容, 共 379.3 次阅读, 收获喜欢 1719 次。

关注

评论

发布
暂无评论
发现更多内容

用 nodejs 搭建脚手架

coder2028

node.js

软件测试 | 测试开发 | Shell 进程通过 ContentProvider 实现跨进程通信

测吧(北京)科技有限公司

测试

leetcode 572. Subtree of Another Tree 另一棵树的子树 (简单)

okokabcd

LeetCode 数据结构与算法

软件测试 | 测试开发 | Spring boot 之 RestTemplate访问

测吧(北京)科技有限公司

测试

Forrester发布中国数据治理生态报告,亚信科技AntDB数据库等四款数智产品入选

亚信AntDB数据库

AntDB AntDB数据库

双非二本程序员,年近30,5年间在大厂中横跳,工资翻了三番

程序知音

Java java面试 后端技术 秋招 Java面试八股文

架构实战营模块1作业

乖乖IvyShine

软件测试 | 测试开发 | 自定义form表单验证

测吧(北京)科技有限公司

测试

认识 ESP-IDF-v4.3+工程结构(ESP32-C3应用调整示例)

矜辰所致

ESP32-C3 9月月更 ESP-IDF

软件测试 | 测试开发 | Golang死信队列的使用

测吧(北京)科技有限公司

测试

医疗卫生机构应该多久进行一次等保测评?

行云管家

网络安全 信息安全 等保测评 等级测评

元年洞察|数字化转型进程中的创新技术菜谱

元年技术洞察

数据中台 数字化转型 趋势研究

AntDB入选《爱分析:2022数据智能厂商全景报告》

亚信AntDB数据库

AntDB AntDB数据库

MySQL查询数据库表记录数

源字节1号

软件测试 | 测试开发 | 利用 rpush 和 blpop 实现 Redis 消息队列

测吧(北京)科技有限公司

测试

运维学网络安全还是云计算好?哪个更有前景?

行云管家

云计算 运维 网络安全

软件测试 | 测试开发 | 一种能有效缓解环境噪声对音频质量干扰的方案

测吧(北京)科技有限公司

测试

仅靠一文便火爆全网!开源阿里绝密800页JDK源码笔记:霸榜GitHub

Geek_0c76c3

Java 数据库 程序员 架构 开发

Eclipse Theia技术揭秘——脚手架源码分析

龙之幽谷

开发工具

软件测试 | 测试开发 | Pytorch GPU 训练环境搭建

测吧(北京)科技有限公司

测试

软件测试 | 测试开发 | InfluxDB 2.0 原理与应用实践

测吧(北京)科技有限公司

测试

javascript 高级编程 之 Array 用法总结

hellocoder2029

Vue

计算机网络——媒体接入控制的基本概念

StackOverflow

编程 计算机网络 9月月更

Eclipse Theia技术揭秘——自定义布局

龙之幽谷

开发工具

数据中台打造企业数据能力组件中心

元年技术洞察

数据中台 SaaS服务应用 PaaS平台化能力

计算机网络——媒体接入控制——静态划分信道

StackOverflow

编程 计算机网络 9月月更

一文读懂“云游戏”

Finovy Cloud

人工智能 云渲染 云游戏

VSCode技术揭秘(一)

龙之幽谷

vscode 开发工具

软件测试 | 测试开发 | gitlab 服务端 hook, 拦截糟糕的提交到仓库

测吧(北京)科技有限公司

测试

边缘计算在视频直播场景的应用与实践

火山引擎边缘云

边缘计算 视频直播 火山引擎边缘计算

AntDB数据库与鼎甲科技完成产品互认证,共筑数据安全防线

亚信AntDB数据库

AntDB AntDB数据库

手把手教你编写HTTP文件测试HTTP API_文化 & 方法_Renato Athaydes_InfoQ精选文章