【玩转 Postman 接口测试与开发2_014】第11章:测试现成的 API 接口(下)——自动化接口测试脚本实战演练 + 测试集合共享

book cover for the 2nd version

《API Testing and Development with Postman》最新第二版封面

文章目录

    • 3 接口自动化测试实战
      • 3.1 测试环境的改造
      • 3.2 对列表查询接口的测试
      • 3.3 对查询单个实例的测试
      • 3.4 对新增接口的测试
      • 3.5 对修改接口的测试
      • 3.6 对删除接口的测试
    • 4 测试集合的共享操作
      • 4.1 分享 Postman 集合
      • 4.2 使用 GitHub 展示

写在前面
终于来到了本章最激动人心的自动化测试实战环节了!用于演示的 ToDo App 项目看似功能简单,实则暗藏玄机。作者虽然只选了几个接口进行演示,但从仅有的几个典型脚本中也可以学到很多实战技巧,比如复用公共的测试逻辑、在当前请求中调用其他现成的接口、利用请求前后脚本实现“无痕测试”……这些精彩内容即便是第二次梳理依旧让人眼前一亮,值得每一位立志深耕 API 接口测试的长期主义者们反复推敲,用心体会。

(接上篇)

3 接口自动化测试实战

……最后给出的 Postman 测试集合结构如下:

图 11.7 用于接口自动化测试的 Postman 集合最终结构

【图 11.7 用于接口自动化测试的 Postman 集合最终结构】

3.1 测试环境的改造

根据前面的设计,下一步应该逐一输入每个接口的 URL、请求参数等等。为方便管理,应该将通用参数放到放到专门的测试环境中,其中包括:

  • base_url:从集合变量迁移到专门的环境中,便于统一管理;
  • task_id:待测试的单个待办项 ID。其值随着测试的进行,很可能不为 1;
  • CALL:这是两个版本中都有提及、却未能补充说明的一个神秘变量。经本人实测,它应该是为了实现请求方法(Method)的 动态切换 而专门设计的一个特殊变量,相当于解耦请求方法。例如按如下方式对 CALL 变量赋初值 GET

img11.19

CALL 变量的用法如下所示:

img11.20

不过,这种动态调用方式可能有违 Postman 接口测试最佳实践,在本书的两个版本中都没有做进一步说明。

关于测试环境的几点重要说明

  1. 对请求方法使用变量:经实测,在 Postman 的请求方法上使用变量时,

    1. 该变量名必须全部大写(CALL);
    2. 但是变量的值可以是小写(get / post 均可);
  2. 变量的初始值与当前值的区别:

    1. 根据书中观点,初始值仅用于给人们提供参考,使用时只用当前值(没说到点子上);
    2. 而根据 Postman 官方文档,初始值(Initial value)会同步到 Postman 服务器,因此不宜存放敏感信息。确需共享敏感信息,建议将其类型设为 secret
    3. 当前值(Current value)不会同步到 Postman 服务器,这些值仅在本地持久化,数据会相对安全些。
    4. 如果后期需要频繁使用敏感信息,建议还是将变量放入 vault 作用域,这样可实现加密存储,以确保敏感数据的安全性。例如:

    图 11.8 利用 Vault 级变量实现数据的加密存储,甚至可以限定域名,且不会同步到 Postman 服务器

    【图 11.8 利用 Vault 级变量实现数据的加密存储,甚至可以限定域名,且不会同步到 Postman 服务器】

3.2 对列表查询接口的测试

接口测试不宜大而全,而应该小步走、多迭代。

对于列表查询类接口 GET /tasks,可以先硬编码,然后再重构成较灵活的形式。例如先对第一个元素进行检查:

const tasks = pm.response.json();
const firstTask = {"id": 77,"description": "Learn API Testing","status": "Complete","created_by": "user1"
}
pm.test("Check first task data", function () {   // Assume that the first task won't changepm.expect(tasks[0]).to.eql(firstTask);
});

上述测试存在明显硬伤:列表的第一个待办项很可能会变化。于是可以略作调整,由元素值绝对相等改为对 key 集的检查:

pm.test("Check that the first task has required fields", function () {const taskKeys = Object.keys(jsonData[0]);pm.expect(taskKeys).to.have.members(['id','description', 'status','created_by']);
});

3.3 对查询单个实例的测试

对于单个待办事项的查询接口 GET /tasks/{{task_id}},其测试逻辑与列表类似,都需要对目标对象的 key 集进行检查。这就涉及重复代码的共享,此时可以将通用脚本放到同一个 文件夹Post-response 层。但示例项目的特殊性在于,列表返回的是一个集合对象(数组)、单个查询只返回一个元素,不能简单共享所有脚本。

此时就不能用文件夹共享脚本了,但可以利用 Postman 全新的私有仓库(package library)导出一个私有的 package 包,例如命名为 common-tests

// in common-tests module
function checkTaskFields(task) {const taskKeys = Object.keys(task);pm.expect(taskKeys).to.have.members(['id', 'status', 'description', 'created_by']);
}
module.exports = {checkTaskFields
}// in Post-response tag
const { checkTaskFields } = pm.require('common-tests');const [task] = pm.response.json();
pm.test("Check first task field", function () {checkTaskFields(task);
});

3.4 对新增接口的测试

对于新增接口 POST /tasks,与查询接口最大的不同在于,出于测试目的新增的临时数据,需要在完成测试后及时清空,即调用删除接口。这样就需要先获取登录令牌。调用登录接口 POST /token 后,需将获取的令牌存入环境变量(例如 token):

图 11.9 调用登录接口后,将获取的令牌存入 token 变量

【图 11.9 调用登录接口后,将获取的令牌存入 token 变量】

注意,这里的 token 作用域无论是集合层还是环境层都行,只是放到集合层的语义更好(测试环境可以指定给其他集合,容易引发不必要的冲突)。

这样新增接口就暗含一个前提:需要提前登录换取令牌(也很合理)。

于是,新增接口的测试脚本可以这样写:

const { checkTaskFields } = pm.require('common-tests');// check for task keys
const task = pm.response.json();
pm.test('Task has a id', function() {checkTaskFields(task);
});// clean up test data
const base_url = pm.environment.get('base_url');
const {id: task_id} = task;
const token = pm.environment.get('token');
const auth = {type: 'bearer',bearer: [{key: 'token',value: `${token}`,type: 'string'}]
};
pm.sendRequest({url: `${base_url}/tasks/${task_id}`,method: 'DELETE',auth
}, function(err, response) {if(err) {console.error(err);return;}pm.expect(response.status).to.eql('OK');
});

实测结果:

图 11.10 包含数据清理逻辑的新增接口实测结果

【图 11.10 包含数据清理逻辑的新增接口实测结果】

为了验证上图中新增的 ID2 任务已被成功删除,可以再查一次列表:

图 11.11 测试完新增接口,再次调用查询接口,以验证新增接口中的数据清空逻辑是否生效(确已生效)

【图 11.11 测试完新增接口,再次调用查询接口,以验证新增接口中的数据清空逻辑是否生效(确已生效)】

最后还需要注意,在新增接口的 Authorization 标签中配置登录令牌,表示只有登录成功的用户才可新增待办事项:

图 11.12 根据获取到的 token 配置新增接口的鉴权类型

【图 11.12 根据获取到的 token 配置新增接口的鉴权类型】

3.5 对修改接口的测试

而对于修改接口 PUT /tasks/{{task_id}} 的测试,则需要先满足两个前提:

  • 用户已登录;
  • 已生成转为修改接口新增的测试数据;

第一项很好实现,直接配置 Authorization 标签即可。

第二项则需要先调新增接口,成功后再对临时新增的数据进行修改。怎样复用新增接口中的创建任务逻辑、同时又不触发新增接口中的测试脚本呢?

这里作者采用了一个非常巧妙的设计:在新增接口的测试脚本末尾,将当前请求直接存入一个环境变量(req):

pm.environment.set('req', pm.request)

实际效果如下图所示:

图 11.13 改造新增接口的测试逻辑,在末尾将本次请求直接存入变量 req 中

【图 11.13 改造新增接口的测试逻辑,在末尾将本次请求直接存入变量 req 中】

然后转到修改接口的 Pre-request 选项卡,读取 req 的值并通过脚本调用新增接口,新增结束后,再将任务 ID 更新到 task_id 中:

// use the 'Create a task' to create a task & set its task_id
pm.sendRequest(pm.environment.get('req'),function(err, resp) {if(err) {console.error(err);return;}const {id: task_id} = resp.json();pm.environment.set('task_id', task_id);}
)

最后切到 Post-response 选项卡,对修改后的内容进行测试:

pm.test('Description matches what was set', function() {const { description } = pm.response.json();pm.expect(description).to.eql('modified task')
});

实测效果:

图 11.14 包含提前新增数据的修改接口测试结果截图

【图 11.14 包含提前新增数据的修改接口测试结果截图】

也可以在浏览器中查看修改结果:

图 11.15 从浏览器再次验证修改接口的测试逻辑(先新增一条,再进行修改。符合预期)

【图 11.15 从浏览器再次验证修改接口的测试逻辑(先新增一条,再进行修改。符合预期)】

3.6 对删除接口的测试

延用修改接口的测试思路,删除接口 DELETE /tasks/{{task_id}} 的测试流程设计如下:

  1. 配置 Authorization 鉴权选项;(与新增、修改接口一致)
  2. 发送请求前先新增一条临时数据,并将其 ID 更新到 task_id 变量中;(与修改接口一致)
  3. 执行删除后,检查响应码是否正常;
  4. 随即利用 task_id 调用单个实例的查询接口,验证是否删除成功。

首先配置登录令牌:

图 11.16 为删除接口配置登录令牌

【图 11.16 为删除接口配置登录令牌】

然后设置请求前脚本:

pm.sendRequest(pm.environment.get('req'),function(err, resp) {if(err) {console.error(err);return;}const { id: task_id } = resp.json();pm.environment.set('task_id', task_id);}
);

接着是删除请求响应后的测试脚本:

pm.test("Status code is 201 or 200", function () {pm.expect(pm.response.code).to.be.oneOf([200, 201]);
});const base_url = pm.environment.get('base_url');
const task_id = pm.environment.get('task_id');
pm.sendRequest({url: `${base_url}/tasks/${task_id}`,method: 'GET'
}, function(err, resp) {if(err) {console.error(err);return;}console.log(`resp.status: ${resp.status}`);pm.expect(resp.status).to.eql('Not Found');
});

实测结果如下:

图 11.17 先新增、再删除、最后再查询验证的删除接口实测效果图

【图 11.17 先新增、再删除、最后再查询验证的删除接口实测效果图】

此外,也可以从线上的 GitPod 后台看到三次请求的日志信息:

图 11.18 从 GitPod 看到的删除接口实测日志信息截图

【图 11.18 从 GitPod 看到的删除接口实测日志信息截图】

4 测试集合的共享操作

4.1 分享 Postman 集合

公开分享

  • 将集合和环境移至公共工作区(public workspace)。
  • 生成公共链接或嵌入代码,方便他人访问。

注意事项

  • 确保不泄露敏感信息(如 API 密钥、内部数据)。
  • 遵循组织的安全政策。

备注

经本地实测,共享测试集合的操作非常简单,都是可视化的流程;只不过要是之前的工作区为 仅本人可见,则 Postman 会默认共享到某个小组,并让你输入组员帐号;否则需要先将该集合、环境移动到一个公共空间,再点共享:

img11.32

唯一需要注意的是,此前创建的私有模块、公共函数等脚本在共享时都将失效(私有模块暂不支持共享操作)。

4.2 使用 GitHub 展示

  • 创建 GitHub 仓库
    • 上传 Postman 集合和环境文件。
    • 使用 Markdown 编写文档,说明测试用例和运行方法。

后记
虽然我本人不是专职测试,但自认对 Postman 也算比较了解了,学了这章内容后,感觉 Postman 还有很多彩蛋功能有待发掘。庆幸自己没有被前半章的冗余描述困住脚步,也没有想要敷衍了事的心态,否则就会和这本书的精华内容无缘了。既然要学,就得把整本书最难的部分给啃掉,不给后续的精进挖坑;毕竟坑挖多了迟早是要还的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/13677.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

华为支付-免密支付接入免密代扣说明

免密代扣包括支付并签约以及签约代扣场景。 开发者接入免密支付前需先申请开通签约代扣产品(即申请配置免密代扣模板及协议模板ID)。 华为支付以模板维度管理每一个代扣扣费服务,主要组成要素如下: 接入免密支付需注意&#x…

Redis - 全局ID生成器 RedisIdWorker

文章目录 Redis - 全局ID生成器 RedisIdWorker一、引言二、实现原理三、代码实现代码说明 四、使用示例示例说明 五、总结 Redis - 全局ID生成器 RedisIdWorker 一、引言 在分布式系统中,生成全局唯一ID是一个常见的需求。传统的自增ID生成方式在分布式环境下容易出…

YOLOv11实时目标检测 | 摄像头视频图片文件检测

在上篇文章中YOLO11环境部署 || 从检测到训练https://blog.csdn.net/2301_79442295/article/details/145414103#comments_36164492,我们详细探讨了YOLO11的部署以及推理训练,但是评论区的观众老爷就说了:“博主博主,你这个只能推理…

用Python获取股票数据并实现未来收盘价的预测

获取数据 先用下面这段代码获取上证指数的历史数据,得到的csv文件数据,为后面训练模型用的 import akshare as ak import pandas as pd# 获取上证指数历史数据 df ak.stock_zh_index_daily(symbol"sh000001")# 将数据保存到本地CSV文件 df.…

RK3576——USB3.2 OTG无法识别到USB设备

问题:使用硬盘接入到OTG接口无热插拔信息,接入DP显示屏无法正常识别到显示设备,但是能通过RKDdevTool工具烧录系统。 问题分析:由于热插拔功能实现是靠HUSB311芯片完成的,因此需要先确保HUSB311芯片驱动正常工作。 1. …

RabbitMQ深度探索:前置知识

消息中间件: 消息中间件基于队列模式实现异步 / 同步传输数据作用:可以实现支撑高并发、异步解耦、流量削峰、降低耦合 传统的 HTTP 请求存在的缺点: HTTP 请求基于响应的模型,在高并发的情况下,客户端发送大量的请求…

maven如何不把依赖的jar打包到同一个jar?

spring boot项目打jar包部署: 经过以下步骤, 最终会形成maven依赖的多个jar(包括lib下添加的)、 我们编写的程序代码打成一个jar,将程序jar与 依赖jar分开,便于管理: success: 最终…

网络工程师 (21)网络的性能

一、速率(数据率或比特率) 定义:数据在数字信道上传送的速率,通常以比特每秒(bps)为单位。常见的速率单位还有千比特每秒(kbit/s)、兆比特每秒(Mbit/s)和吉比…

UE5 蓝图学习计划 - Day 14:搭建基础游戏场景

在上一节中,我们 确定了游戏类型,并完成了 项目搭建、角色蓝图的基础设置(移动)。今天,我们将进一步完善 游戏场景,搭建 地形、墙壁、机关、触发器 等基础元素,并添加角色跳跃功能,为…

计算机毕业设计hadoop+spark+hive民宿推荐系统 酒店推荐系统 民宿价格预测 酒店价预测 机器学习 深度学习 Python爬虫 HDFS集群

温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…

金蝶云星空k3cloud webapi报“java.lang.Class cannot be cast to java.lang.String”的错误

最近在对接金蝶云星空k3cloud webapi时,报一个莫名其妙的转换异常,具体如下: 同步部门异常! ERP接口登录异常:java.lang.Class cannot be cast to java.lang.String at com.jkwms.k3cloudSyn.service.basics.DeptK3CloudService.…

html的字符实体和颜色表示

在HTML中,颜色可以通过以下几种方式表示,以下是具体的示例: 1. 十六进制颜色代码 十六进制颜色代码以#开头,后面跟随6个字符,每两个字符分别表示红色、绿色和蓝色的强度。例如: • #FF0000:纯红…

老游戏回顾:G2

一个老的RPG游戏。 剧情有独到之处。 ------- 遥远的过去,古拉纳斯将希望之光给予人们,人类令希望之光不断扩大,将繁荣握在手中。 但是,暗之恶魔巴鲁玛将光从人类身上夺走。古拉纳斯为了守护人类与其展开了一场激战&#xff0c…

E4982A,keysight是德科技台式LCR表

是德科技keysightE4982A台式LCR表 是德KEYSIGHT的精密型LCR表E4982A,针对SMD电感器、EMI滤波器等无源元器件的制造测试展现出卓越性能,特别适用于1 MHz至3 GHz高频率范围内的阻抗测试。此外,E4982A还广泛应用于研发领域,凭借其强…

C++, STL容器 array:固定大小数组深度解析

文章目录 引言一、设计哲学与底层实现1.1 零抽象成本的封装1.2 性能特征二、内存优化实践2.1 缓存友好性对比2.2 内存碎片防护三、高级内存管理技巧3.1 精准内存对齐3.2 内存复用模式四、工程实践指南4.1 适用场景4.2 陷阱规避五、未来演进结语引言 在C++标准库中,std::array…

013-51单片机红外遥控器模拟控制空调,自动制冷制热定时开关

主要功能是通过红外遥控器模拟控制空调,可以实现根据环境温度制冷和制热,能够通过遥控器设定温度,可以定时开关空调。 1.硬件介绍 硬件是我自己设计的一个通用的51单片机开发平台,可以根据需要自行焊接模块,这是用立创…

(苍穹外卖)项目结构

苍穹外卖项目结构 后端工程基于 maven 进行项目构建,并且进行分模块开发。 1). 用 IDEA 打开初始工程,了解项目的整体结构: 对工程的每个模块作用说明: 序号名称说明1sky-take-outmaven父工程,统一管理依赖版本&…

车载以太网__传输层

车载以太网中,传输层和实际用的互联网相差无几。本篇文章对传输层中的IP进行介绍 目录 什么是IP? IP和MAC的关系 IP地址分类 私有IP NAT DHCP 为什么要防火墙穿透? 广播 本地广播 直接广播 本地广播VS直接广播 组播 …

UE5 蓝图学习计划 - Day 12:存储与加载

在游戏开发中,存储(Save)与加载(Load) 系统至关重要,玩家需要能够保存游戏进度、角色状态、道具数据等信息,并在下次启动游戏时恢复它们。UE5 提供了 SaveGame 蓝图类,帮助开发者快速…

web-文件上传-CTFHub

前言 在众多的CTF平台当中,作者认为CTFHub对于初学者来说,是入门平台的不二之选。CTFHub通过自己独特的技能树模块,可以帮助初学者来快速入门。具体请看官方介绍:CTFHub。 作者更新了CTFHub系列,希望小伙伴们多多支持…