产品战略专家梁宁确认出席AICon北京站,分享AI时代下的商业逻辑与产品需求 了解详情
写点什么

手把手教你编写 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:484094
用户头像
王强 技术是文明进步的力量

发布了 823 篇内容, 共 431.0 次阅读, 收获喜欢 1750 次。

关注

评论

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

用Python绘制专业的K线图【含源代码】

恒生LIGHT云社区

拥抱开源,共建生态 - 开源生态与效能提升专场 | CIF 精彩看点

CODING DevOps

DevOps 研发效能 腾讯云 CIF 峰会 开源生态

超十年渗透专家总结出636页渗透测试全笔记,100课时一次讲清

Java 架构 面试 程序人生 编程语言

使用 grpcurl 通过命令行访问 gRPC 服务

AlwaysBeta

golang gRPC

搞不懂云原生

二哥不再迷茫

从工具、工具箱到数字化软件工厂——DevOps 设计理念与工程实践专场 | CIF 精彩看点

CODING DevOps

DevOps 数字化 研发工具 腾讯云 CIF 峰会

浪潮云洲荣获两项工业自动化及数字化行业年度大奖 inspur浪潮云 昨天

云计算

智能网联汽车行业信息安全现状与威胁

SOA开发者

互斥锁、自旋锁、读写锁...理清它们的区别和应用

行云创新

云计算 编程 开发 应用

行云创新:云原生技术助力企业数字化转型

行云创新

技术 云原生 转型 数字化 平台

如何让文件共享 SDK 支持使用 Uri 上传文件

ZEGO即构

文件存储 分区存储 文件共享

掘金热榜第一!阿里P8用近十个月整理出来999页Java岗核心笔记限时开源!

Java 架构 面试 程序人生 编程语言

四面字节跳动(高级开发岗):分布式+中间件+TCP+JVM+Hashmap

Java 编程 架构 面试 计算机

阿里巴巴架构师十年整理出的JavaSpringBoot核心文档,真是太全了

Java 架构 面试 程序人生 编程语言

AlibabaP9力荐!最新出品1297页JDK源码+并发核心原理解析小册

Java 架构 面试 程序人生 编程语言

【新品尝鲜】OCR磅单识别上线邀测,为货运物流提速增效

百度大脑

人工智能 OCR

金九银十不要怕!有了腾讯这本2021年最新Java面试手册,offer手到擒来!

Java 程序员 架构 面试 后端

史上最全Java高频面试合集,命中率高达95%

Java 程序员 架构 面试 后端

手把手教你使用Studio Lite + Digtal car!助力智能汽车场景、轻应用开发更轻松!

SOA开发者

重磅来袭,虚拟化技术分类

hanaper

目睹阿里技术官写的Tomcat架构笔记后,瞬间觉得自己是渣渣

Java 架构 面试 程序人生 编程语言

如何做一场有趣又高效的迭代回顾会议?

万事ONES

Scrum 敏捷 回顾会

艾瑞发布《2021年中国企业级 SaaS 行业研究报告》,ONES 入选典型厂商案例

万事ONES

项目管理 SaaS 协同办公

音视频终端引擎优化实践

百度开发者中心

最佳实践 音视频 实践案例 智能视频 行业深度

东软熙康、百度、京东方,互联网医院的三个典型样本

海比研究院

提高工作效率的三种方法

石云升

团队管理 管理 引航计划 内容合集 9月日更

不得不聊一聊英语爱好者的单词杂货铺了

小匚

随笔杂谈 生活记录 英语 大学英语四六级 单词

图谱相关技术在风控反作弊中的应用和探索

百度Geek说

后端 软件架构

快手、知乎等平台严厉打击“病媛”炒作行为:自媒体行业不能被流量裹挟

石头IT视角

华为云带你探秘Xtrabackup备份原理和常见问题分析

华为云数据库小助手

GaussDB 华为云数据库 MySQL 数据库 GaussDB(for MySQL)

智能大数据专场,百度智能云带来智能大数据产品架构全景图

百度大脑

人工智能 大数据

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