前言
终于整理到了接口测试部分的内容,接口测试可以说是软件测试入门到初级软件测试的一个必备进阶技巧。很多挂着“灰盒测试”的标识,其实就是对接口测试的另外一层理解。何为“灰盒”,能够看到一部分本质的东西,接口测试就是这样,根据代码可见度来说接口测试能够看到我们实际上发出的请求数据和响应数据。接口测试可以很好的绕过前端局限在界面上面的点点点,更直接地接触到实际http协议里对于服务器的原理应用,所以学习接口测试必然是一位软件测试人员应知应会的知识储备和技术。
**这篇文章会比较冗余,不仅是进行基本的接口测试的理论介绍,详细的温习http协议,也会介绍接口测试当中常用的postman测试工具的使用方法,最后会涉及到一点点接口自动化的部分。**
1.接口测试理论
1.1概念
接口:**系统之间(可以是外部的系统与内部的系统,也可以是内部和内部之间的系统)数据交互的通道。 接口在系统里的本质理解就可以作为函数或者说是方法。**
接口测试:**校验 接口回发的 响应数据 与 预期结果 是否一致**
下图,就是客户端与服务器之间的实际交互原理图(自己画的手残党勿cue)
客户端登陆我们常见的账号+密码的请求就会被发给我们的服务器,然后服务器回响应触发成功跳转的事件
1.2接口测试的作用和常见学习方式
作用:
** 1.能够发现页面测试实现不了的问题**
** 2.符合质量控制前移的理念**
3.低成本,高收益
首先,我们知道关于用户登陆这一部分是非常吃安全性能的,一个是抓包是否能过滤掉账户密码为明文的操作,另外一个重要的点则是看输入错误的请求数据是否能够通过登陆。啊,肯定会有人疑惑账户或者密码输入了错误的请求数据为什么还能通过呢?**答案是sql注入。**
很简单,我们知道这一条条的和用户相关的数据都是存储在数据库服务器当中的。我们通过对数据库的远程连接进去能够看到数据库当中的一些数据,比如账户是admin,密码是123;那么我们肯定是用admin或者123登陆的,如果这时靠谱的产品经理会对账户和密码进行长度及数据的限制,我们在前端页面上直接进行输入的测试可能就用不了这个方法,因为长度可能会大于,这样我们在界面测试一是没有考虑到这个异常手段绕过的检测,二是没有排除掉这个安全隐患。下图就是该方法进行的sql注入。![](https://img-blog.csdnimg.cn/c699d16d49924678b7063b982a6796fe.png)
当然了这是一个经典的安全漏洞,现在基本不会有这样明显的问题,这样的注入方式就是采用sql语句中的逻辑判断永恒为真的方式来绕开登陆的界限。最典型的排查是否可以使用sql注入的方法就是利用url传参当中的参数加一个单引号来验证返回是否错误,具体可以参照底下这篇关于sql注入的基础文章进行了解和学习,这里仅带过。sql注入基础原理(超详细)_牛牛Blog的博客-CSDN博客_sql注入攻击的原理s
那么如何实现接口测试呢?也是有两种方式,这篇文章重大会来讲解工具实现简易的接口测试
1.工具实现
postman:使用简单,但是上手难度低,功能少
jmeter:使用难度大一些,但是功能齐全,且能够做到较简单的性能测试
2.代码实现
Python+request+Unittest
java+httpclient
1.3HTTP协议
其实这也是老生常谈的了,先前在web和app的项目测试里都有提到过HTTP协议的介绍。在这里还是重新回滚一遍。
协议:就是规则,要求使用协议的对象必须遵守。
http协议:中文的意思就是超文本传输协议,它是属于OSI七层协议当中最顶层的应用层。它的特点就是客户端/服务器的模式,它是简单快速且灵活的,类似于udp的特性所以它也是无连接无状态的。
1.3.1URL介绍及https加密
** URL格式:URL组成 - 协议://hostname[:port]/path/[?查询参数1&查询参数2]**
[ ]里的部分不一定要有
hostname:ip地址也就是域名,dns解析中的dn就是域名,唯一定位一台主机,s=服务器
port端口号:作用是为了在主机上有唯一定义一个应用程序;省略掉的话默认http跟80端口,https跟443端口
path资源路径:作用是应用对应的数据资源,也可以省略,省略万资源路径为 “/”
查询参数:作用是给资源传递参数,可以省略,没有?分隔符;可以有多组查询参数,以k=v的格式,各组之间用“&”隔开。
例如:https://taobao-test/index.php?m=Home&c=User&a=do_login
这里常见的协议:http https 指定数据传输的规则;http是明文传输像一些敏感数据就不适合用http协议;https的s就是secure,它是由http协议进行通信,但是是用SSL/TSL来进行数据包的加密。
这里我再重新进行https的一个补充,用HTTPS协议需要用到CA(certificate Authority 数字证书认证机构)申请证书,一般免费证书较少因此需要一定费用。HTTP 页面响应速度比 HTTPS 快,主要是因为 HTTP 使用 TCP 三次握手建立连接,客户端和服务器需要交换 3 个包,而 HTTPS除了 TCP 的三个包,还要加上SSL握手需要的 9 个包,所以一共是 12 个包。为什么要用到这个证书,**因为如果不是这个证书作为”公正的第三方“,那么被”邪恶的第三方“截取到了密钥对,那么基本上和明文传输没有什么区别。所以CA证书是用来证明公开密钥是货真价实的密钥而不是被调换的。**
https 的请求和http是一样的,在浏览器中输入一个网址然后连接到server 的443端口。不过采用https的服务器必须要有一套数字证书,可以自己制作,也可以向组织申请,区别就是自己办的证书需要客户端通过才可以继续访问,向公司申请的证书则不会弹出提示页面(startssl就是个不错的选择,有1年的免费服务) 而这套证书里就是包含一对非对称密钥对(公钥和私钥),如果对公钥和私钥不太理解,可以想象成一把钥匙和一个锁头,只是全世界只有你一个人有这把钥匙,你可以把锁头给别人,别人可以用这个锁把重要的东西锁起来,然后发给你,因为只有你一个人有这把钥匙,所以只有你才能看到锁起来的东西。下图即为原理,依然是基于客户端和服务端之间的请求和应答。
上面说的这个**数字证书其实就是公钥(钥匙头)**,只是包含了很多信息,比如证书的颁发机构还有过期时间等。**客户端会解析证书,由客户端的TLS来完成,首先会验证公钥是否有效**(一般浏览器里自己都会存储常见的受信赖的CA机构,还有过期时间等)发现异常会弹出警告。如果证书没有问题,就会生成一个随机值(相当于客户端自己根据公钥-锁头搞了一个私钥),**然后用证书对该随机值进行加密**,就好像上面说的,把随机值用锁头锁起来,这样除非有钥匙不然看不到锁住的内容。
传输加密信息,这部分传送的是用证书加密后的随机值,目的就是为了让服务端得到这个随机值,然后客户端和服务端的通信就可以通过这个随机值来进行加密和解密了。
服务端解密信息:当服务端解密之后,能够获得客户端传过来的随机值(私钥),**把内容通过这个值进行对称加密(意思就是同一个密钥可以同时作为信息的加密和解密),**所谓对称加密就是将信息和私钥通过某种算法混合在一起,这样除非知道私钥,不然无法获取呢你人,而正好客户端和服务端都知道这个私钥,所以只要加密算法够厉害私钥够复杂,数据就足够安全,即使第三方监听到了也是束手无策。
在客户端传输给服务端随机key之后,服务端再用私钥加密的信息给客户端可以被客户端的私钥解密,获取了解解密后的内容。
要注意:https的加密方式是结合了对称加密和非对称加密,也就是说是用非对称加密的方式来传输对称加密过程中的密钥,之后就可以采取对称加密的方式来传输数据。
1.3.2HTTP请求
产生端:一定在客户端产生。 当客户端给服务器发送数据时,使用该协议(请求报文,请求包)
请求行:请求方法,URL,协议版本
请求头: k:v (键值对形式)
空行:代表 请求头 结束
请求体:发送给服务器请求时,携带的数据
如下图,就是一个HTTP请求的内容格式
示例:
POST http://demo.zentao.net/user-login.html HTTP/1.1
Host: demo.zentao.net
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:68.0) Gecko/20100101
Firefox/68.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: http://demo.zentao.net/user-login.html
Content-Type: application/x-www-form-urlencoded
Content-Length: 54
Connection: keep-alive
Upgrade-Insecure-Requests: 1
account=demo&password=efc4a3b32e48054865e5a8321cfda3e4
** 请求行:**
一定位于http请求协议的第一行。格式:请求方法 URL 协议版本
请求方法(restful风格)
** get:查询 -- 没有请求体**
** post:添加(注册/登陆)**
** delete:删除 -- 没有请求体**
** put:修改**
协议版本
常见 HTTP/1.1
请求头:
位于 请求行只想,空行之上的部分。数据组织格式 一定是 k:v 对
记忆!!请求头 Content-Type
application/json:请求体数据类型为json
application/x-www-form-urlencoded:请求体数据类型为表单类型
请求体:
位于 空行之下
有的请求协议 是没有请求体。例如上面说的 get,delete
请求体的数据类型,受请求头中Content-Type的值影响。
例如,打开我们的浏览器按f12或者右键进入开发者管理工具,使用我们的抓包工具来进行分析,随机找一个登陆的界面来查看
需要注意表单类型的数据和json类型的数据,这个在后续的接口测试当中是很重要的!!
1.3.3HTTP响应
产生端:一定产生在服务端。 当服务器接收到http请求协议后,才会产生http响应协议(响应报文,响应包)
整体格式类似于HTTP请求
响应行:协议版本 状态码 状态码描述
响应头:k:v格式数据
空行:代表响应头 结束
响应体:服务回头发给客户端的 数据。几乎 所有的 响应包,都有响应体。
示例:
HTTP/1.1 200 OK
Date: Fri, 22 May 2009 06:07:21 GMT
Content-Type: text/html; charset=UTF-8
<html> <head></head> <body>...</body> </html>
状态行:
一定位于响应协议的,第一行,格式:协议版本 状态码 状态码描述
状态码 5类:
1xx:指示信息
2xx:成功 一般是200
3xx:重定向
**4xx:客户端错误 **
5xx:服务端错误
常见的状态消息和说明见下图:
响应头:
位于 响应行之下,空行之上的部分。 数据组织格式一定是 k:v 对
响应体:
位于 空行 之下
几乎所有 响应协议 都有响应体
响应体中 包含的数据,是接口测试过程中,所要使用的 实际结果(不是预期结果)
1.4接口规范
1.4.1传统接口
刚刚上面其实也有提到,我们一般来说最常见的请求方法就是get和post,而传统接口就是利用这两个请求方法来实现所有操作的。 缺陷就是 url与资源不是一一对应的。**我们只能在url中看出,是什么样的操作,且状态码统一返回都是200**。例如下图所示
1.4.2restful风格接口
接口使用的方法和http协议的 请求方法 一一对应
get 查询 post 添加 put 修改 delete 删除
这个方法使用的好处是响应状态码会比较全面,但是需要结合请求方法才能识别操作,如下图
1.4.3 get和post的区别
既然一直在强调这两个http请求常用的请求方法,也说明了二者对于查询和添加其实都可以使用,那么他们的区别又在哪里呢?
1.get请求比post不安全,因为get请求的请求参数是直接在url里体现的,而post的请求参数是在请求体里的,前面有说过get是没有请求体的,因此get请求不能用来传输敏感信息
2.既然get请求在浏览器当中有请求参数,每个人浏览器的搜索框都是有长度限制的,因此get请求的参数长度会被限制,而post请求的请求参数长度就不会被限制,因此get请求参数的数据量一般也比post请求参数小
3.get请求参数直接受ascii字符,而post没有限制
上面都是应用层协议来说的区别,如果从传输层来看,二者虽然都是基于tcp进行传输的,get请求浏览器会把http header和data一起发出去,而对post来说,浏览器会先发header等服务器响应100 continue再发送data,所以post需要两包的tcp数据包,get性能会更好于post,只不过也不是所有浏览器用post都是发两包,Firefox就只发一次。
1.5接口测试流程
首先,我们要知道**测试的流程依然是先前的那六个步骤,需求评审,计划编写,用例设计,执行用例,缺陷管理,测试报告**
在接口测试的流程里,稍微能有一些不同的地方就是我们需要多分析一份接口的文档,这个是开发编写的 接口API文档,然后同样需要对用例进行设计,比如说我们设计的是接口测试的用例,编写的格式也是使用Excel表格的形式。准备接口测试的脚本,一般用工具我们会自动生成脚本,代码的话则需要自己来写。最后到执行用例这一步,我们也会遇到异常抛出,需要对缺陷进行跟踪。最后生成接口测试的报告。当然还有更近一步的选择,也就是接口自动化持续集成,这个难度会大很多。在这里我就不提议。
1.5.1接口文档
接口文档其实就是API(application program interface)文档,一般是由后端开发工程师来编写,用来 描述 接口信息的 文档。
接口文档的作用:
协同:团队人员工作协同配合
约束:项目更新修改同步维护
1.5.2解析接口文档
通过分析接口文档,熟悉接口信息
通过接口文档获取 接口测试 所使用的 请求数据和预期结果,最终写出接口测试用例!
解析的核心目标:
1.请求报文关键数据
**请求方法,URL,请求数据(请求头,请求体)**
2.响应报文关键数据
**响应状态码,响应数据(响应体)**
下图为一个标准的接口测试用例:
1.5.3接口测试点(or测试维度)
其实,这里如果和我们功能测试走的流程一样的话,无外乎也是我们以软件质量模型来要求的那些个测试点,但是有看到有更好的接口测试维度总结,来自黑马程序员官方提到的:接口的功能测试,接口的性能测试,接口的安全测试。通过这三个方向,我们也省去了很多冗余的总结,看下图,就能够很好地理解这三个测试维度。![](https://img-blog.csdnimg.cn/d6087a23800247688864a05c02787dfe.png)
功能测试部分:
单接口功能:
手工测试中的单个业务模块,一般对应一个接口。
登录业务 ——> 登录接口
加入购物车业务 ——> 加入购物车接口
订单业务 ——> 订单接口
支付业务 ——> 支付接口
借助工具、代码。绕开前端界面,组织接口所需要的数据,展开接口测试。
** 业务场景功能:**
按照用户实际 使用场景,梳理 接口业务 场景。组织业务场景时,一般只需做 正向 测试即可(与手工一致)。
一般建议用最少的 用例 覆盖最多的业务场景。如底下两个案例:
登录 —— 搜索商品 —— 加购物车 —— 下单 —— 支付 —— 评价,
登录 —— 添加员工 —— 查询员工 —— 修改员工 —— 删除员工 —— 查询员工
注意:其他部分因为涉及到比较难的点我这里也不提,且此次接口测试当中使用的工具也无法实现性能方面的关注点。
2.接口测试工具
2.1postman介绍
Postman是一个可扩展的API开发和测试协同平台工具,可以快速集成到CI/CD管道中。旨在简化测试和开发中的API工作流。简而言之,就是一款开发和测试都能用的调试和测试的工具。
2.2postman安装和环境配置
不懂就问,为什么我们要选择postman呢?一句话,因为它简单好上手且易于多人协作。postman虽然简单,但是能干的事情可不少,能够为API调用来创建集合实现多个请求,可以使用不同的环境来减少重复的测试,也可以使用断言检测来确保测试覆盖率,还能用集合runner或者newman实现工具自动化测试,最后难度最大的持续集成也是支持的。
下载postman的方法也很简单,第一步:官网主页Download Postman | Get Started for Free
下载所需版本即可。
第二步:在安装完成之后要求你必须登陆才能使用,没有账号可以进行注册,注册是免费的。(也可使用Google账号,不过基本不能登录,你懂的)
在启动前的最后一步,也就是在workspace里选择你要使用的工具然后点击“save my preference”。这里需要拓展一点就是workspace是postman里的一个概念,作为一个工作空间它又分为personal和team类型,personal只能看自己的API,team workspace是可以添加成员和设置成员权限的,不过呢如果是个人登陆还是推荐不要登陆,登录之后的测试历史数据会被保存下来。有的API的数据是很敏感的,包含Token或者就是私密信息,即使postman自己也强调不会窥探信息,但是像一句话说的“网络并没有绝对的安全”。所以最好的方法还是手动拷贝,每次测试之后可以将数据(case)保存到本地,下次再将case导入即可。
通过上图能够看到说如何进入postman里的workspace测试了,下图就是启动后的页面了
2.3Postman基础使用
2.3.1常见按钮
下面我会先根据一些常见到的按钮来进行解释,然后再讲一些核心的业务流程和核心功能(按照一个软件的熟悉方法来进行解释),有的人可能是英文版本看不懂可以对照着我的图片。
1.New(新建):在这里我们能够创建新的请求,集合或者环境,还可以创造更高级的文档,mock server和monitor以及API。
2.import(导入):这用于导入集合或环境。有一些选项,例如从文件,文件夹导入,链接或粘贴原始文本。![](https://img-blog.csdnimg.cn/8bbe3e30ff9a490980adaa9f688b81ac.png)
3.Run(运行):通过Collection Runner执行自动化测试,后面会讲。
4.My Workspace:这个就是一个工作区,可以是团队也可以是个人的,底下有很多集合,即合里会包含很多的接口也就是API
5.Invite:不用多说,就是邀请别的同事一起来协同工作,我是没有用过
6.History:所有请求的历史记录,这样你能够容易跟踪你所做的操作
7.Collections(集合):这就是一直在说的集合了,按代码来说其实它就是一个测试套件,像代码里一个测试套件中也是有很多的方法,方法也或者说是函数,它就是接口也可以说是request(请求)![](https://img-blog.csdnimg.cn/23cd2be83ec540398a00df758a2564fe.png) 8.request:上面说到的请求,也是和集合添加的方法一样,要么在“...” 当中添加,要么在“+”号中添加。这里的request就是一个请求。上面的集合相当于一个模块。
9.Method:这里就是请求方法了,其实在前面的http请求当中有讲过请求行的格式,看下图就能看清楚基本的这个接口构造。
10.params(参数):在这里就是编写所需要的请求参数了,如前面说的k:v这样的键值对格式,key就是参数名,value就是参数的值![](https://img-blog.csdnimg.cn/32808b2c21b744fd837625270cc344eb.png)
**11.authorization(授权)**:这his为了访问api,需要适当的授权。它可以是Username,password也可以是Token等。
12.headers:请求头信息,在浏览器开发者工具当中也能见到
13.Body:请求体信息,像get和delete请求方法里是没有请求体的,在post当中常见
14.Pre-request Script:请求之前 先执行脚本,使用设置环境的预请求确保(用的少)
**15:Tests(断言测试):**这个测试非常重要,这些脚本是在请求期间执行的,我们用来设置检查点来验证响应状态码和响应数据是否符合预期。
16.setting:这个设置里面基本不怎么会用到,其实就是ssl证书和自动重定向的默认开启。
2.3.2如何处理get请求
1、选择HTTP请求方式为GET
2、在URL区域输入 链接
3、点击 “Send”按钮
4、你将看到下方返回200状态码 ok![](https://img-blog.csdnimg.cn/e4bbf670cc094f6093c21f5d057762c7.png)
如果在某些情况下,get请求失败可能由URL无效或需要身份验证。
2.3.3如何处理post请求
**表单格式:**
post请求与get请求不同,因为存在用户向端点添加数据的数据操作。常见的进行post请求的方法就是在web登陆或者注册的界面里进行登陆,当然现在的登陆界面都有了验证码这样比较麻烦的数据,因为没有开发提供的详细的文档,这里我默认一个使用的环境和情景,是不需要验证码登陆的。
还是一样,我们使用post请求做接口,还是要用把请求方法和对应的url先填写,这是请求行部分的内容;然后到请求头的部分,和get请求那样简单的查询不同,post需要添加请求参数,因此请求头里需要注意关键词Content-Type,也就是内容类型,而它的值在上面也着重强调了,我们需要分析是表单类型的还是json类型的,这里假设是表单类型的(商城类)那么它的value就是application/x-www-form-urlencoded(这个最好不要自己手写能复制就复制不然容易出错),请求体的内容。![](https://img-blog.csdnimg.cn/7279024496794da4824fc17927bf2ab4.png)
最后如果在响应体当中返回一组正常数据,并且状态码正常说明了是post请求发送成功
j**son格式:**
同样的,在请求头当中,把对应Content-Type的值改为application/json即可;但是在请求头体当中没有上面表单对应的x-www-form-urlencoded勾选,而是要点击raw,然后选择下拉列表里的json数据格式进行填写,如下图所示就能得到响应结果了,主要**观察美化后的响应体**。
2.4 Postman进阶使用
2.4.1 响应结果自动断言
响应结果是根据请求发送后应答的,这时候如果让响应的结果能够替代我们人工来进行自动判断,那是不是也算是用工具实现测试的自动化?何为判断?那就是让响应数据里的实际结果和我们的预期结果是否能达成一致。如下图所示,即为postman做断言功能的界面
这里还有一个断言的概念需要拓展一下,什么是断言?
断言(assertion):是一种在程序中的一阶逻辑(一个结果为真或假的逻辑判断式),目的为了表示验证开发者预期的结果--当程序执行到断言的位置时,对应的断言应该为真。若断言不为真时,程序会中止执行,并给错误信息。
例如,在python当中我们就会在unittest框架当中使用常见的断言方法,例如assertEqual(预期结果,实际结果)和assetIn(预期结果,实际结果);通过Equal和In的翻译,也能比较清晰的理解到说assertEqual就是预期结果和实际结果如果相等的情况下就会返回true,不通过就会抛出异常,assertIn则是判断预期的一个结果是否包含在实际结果中,如存在就返回true 用例会通过,否则不存在就会抛出异常。
而postman的断言代码(ps:因为代码量不大,后面统一用脚本来解释) 一般是书写在Tests标签页中---使用的语言是JavaScript,查看断言结果在 Test Result标签页当中,最后会返回的断言结果就是(PASS/FAIL)。不过要记住,这里的断言它的一个**工作时机是在服务器进行响应包返回给postman之后,才开始解析http当中的响应包、状态码、响应体,执行断言脚本。**
最最最常用到的postman里的断言脚本是以下的三个!!!
1.Status code:Code is 200
** 断言响应状态码是不是为200**
2.Response body:Contains string
** 断言响应体JSON数据**
3.Response body:JSON value check
** 断言响应体是否包含指定字符串**
当然也有其他的snippets(代码段),这个在postman里大家自己进行查看就可以,其实都是很好理解英文的意思的。主要再来说说这三个小代码段的解析,JavaScript语言相对来说理解也比较容易。
tip:常见的单行注释符号,如JS里的是//,python里的是# ,html里的是,sql语句里的单行是--或者"/"、"/"。
ex1:
pm.test("Status code is 200", function () {
pm.response.to.have.status(200);
});
这里的pm,就代表postman的实例;test()就是 postman里实例的测试方法,这个方法是允许有两个参数,参数1就是"Status code is 200"这个参数**可以任意修改,不影响断言---其实就是显示文字标题名称的意思**,参数2是一个匿名函数的调用。
pm.response.to.have.status(200); //这里填写的200是预期结果,实际结果是请求后返回的结果。
ex2:
pm.test("Body matches string", function () {
pm.expect(pm.response.text()).to.include("string_you_want_to_search");
});
和上面的ex1一样,这里的语句格式也是实例然后引用方法,里面使用一样的参数格式;第二行的脚本就是expect实例方法用来期待判断**返回的实际结果里面包含的预期结果的值**。
这个用的在这三个当中算是最少的,举个例子:我们直接使用默认生成的脚本来查看返回的数值是什么就可以。
不难看出,我们pm.expect(pm.response.text())这一小段的脚本返回的数据其实,就是提取到的响应数据的文本:![](https://img-blog.csdnimg.cn/85a44e778aae40aeb858cb68e397b75e.png)
那么后半句的包含其实很容易理解,只要我们是让他处于在这响应体当中的数值,那么就是正确的,比如我们因为是查询天气城市所选的地就是北京,那就在后面的预期结果字符串当中去选择填写"北京"。最后返回的结论就是pass。
这里其实很好理解,只不过我以一种傻瓜的教学方式来解释,它其实也不算是很适用的断言判断,**例如在这里的判断如果我们没有指示性很强的返回数据,来判断其实意义不大,我们即使填一个在这里面无关的形式参数也是可以通过。因为本身是一个包含,只能说是一个比较基础的准入**,和完全的匹配还是有差距。
ex3:
pm.test("Your test name", function () {
var jsonData = pm.response.json();
pm.expect(jsonData.value).to.eql(100);
});
这里的第一句脚本也和前面两个是相同的,不过中间多了一句将整个的json响应体赋值到 变量jsonData上面去,比如说我们刚刚提到的返回的weatherInfo的响应数据内容的值就被引用到了jsonData的地址里,jsonData.value的意思就是响应数据里的实参的值。为什么我前面强调说了json数据,因为json数据的格式就是key:value这样的键值对,所以jsonData.value就是指的这里面所有形参实际传入的实参数据(实参就是实际返回的数值,一般格式就是形参名:实参值),一般对于类似下图的数据来说是最合适用做**值的断言判断,因为只有一层关系。**![](https://img-blog.csdnimg.cn/2094e32af3884e2da58b8efadb52685f.png)
再仔细地把它写的足够具体一些,就会成为我们平常见到的多个断言脚本,标题也可以稍微的进行细节上的修改,就会如下图所示出现这样好看的测试结果。![](https://img-blog.csdnimg.cn/23cd089363044786bdd7c65e41b88d2e.png)
但是呢,用这种方式我们很明显不能断言到有json数据格式像weatherinfo那样的字典形式下还有字典,例如我们想要找城市,那么我们就得改成jsonData.weather.city,在使用jsonData.weather的调用已经有了一整个部分,再使用weather.city那么就是对应是调用城市的形参来获取实际参数。可以达到下图的效果:
除了这种都是字典{}的形式,还有一种列表的形式[](当然我这是以python里的数据存储类型作为解释,其他地方可能不叫列表可以叫数组),这样的形式,我们去取实际的数据就要使用数组的形式了,比如下面的例子:
![](https://img-blog.csdnimg.cn/c343d645646f48dbb347016abc93698b.png)
判断日周期数据store_lists字段,json中第二个字符串store_code是否为"xxxxx6",再看下面的这一小段脚本,很明显能够发现不同的地方,运用到了数组。
pm.test("判断store_lists字段,json中第二个字符串store_code是否为xxxxx6", function () {
var jsonData = pm.response.json();
pm.expect(jsonData.data.store_lists[1].store_code).to.eql("xxxxx6");
小小总结以下:断言其实核心就是一个一阶的逻辑判断,就是判断预期结果和实际结果是否一致。如果为真返回true-pass,否则取反。那么很明显关键步骤就是对实际结果的返回,我们要获取到实际结果,在可见到部分代码的情况下就是让我们知道形参,通过形参来传入实参最后返回实际数据和预期结果进行一个判断。(可能会比较饶一些,但是实际用简单的小案例上手一下,大家就会比较的好理解)
http://www.weather.com.cn/data/sk/101010100.html
上面的这个链接,就是提供给大家作为练习用的,用get的请求方法就可以实现。
2.4.2json文件和csv数据文件
**JSON文件介绍**
这里本来是不想啰嗦,但是还是得拓展一下,因为json格式的文件是在是太常见太重要了!
首先,json文件作为一个文件,它的本质也是文本文件,就可以直接使用 read 和 write 去进行操作,它比较特殊,和python当中的字典和列表相似。它的全程 javascript object notation,是一种**基于文本,独立于语言的轻量级数据交换格式。格式就是.json**
一般格式:(一般来说值的类型可以包含数字-整数或者浮点数,字符串-使用双引号,逻辑值-true和false)数组 -> [] ,对象 -> {}, 空值 -> null,python里的是none。
** json文件,也可以看做是一个对象,或者是数组,对象和数组之间是可以互相嵌套的。**
** json中的对象,是由键值对组成的,键必须是 字符串类型!**
** json中的数据直接用逗号隔开就可以,最后一个数据后面不能加逗号**
[
{
"name":"woman",
"age":18,
"Man":"true",
"like":["music","eat","play"],
"address":{"country":"china","city":"厦门"}
},
{
"name":"man",
"age":81,
"Man":"false",
"like":["rap","drink","play"],
"address":{"country":"china","city":"北京"}
}
]
**CSV数据文件**
其实CSV这三个字母,翻译成英文大家更好理解,它就是comma-sepatated values,意思是什么呢?逗号分隔值,当然有时候也会叫字符分隔值(因为有时候不是逗号分隔),其文件里的数据类型只有数字和字符,相比较json的数据类型少了不少。因此,**它的定义是一种通用的、相对简单的文件格式,被用户、商业和科学广泛应用。在jmeter里导入文件,我们用csv就可以做大量的简单数据来测试一些简单的性能测试,比如支付系统常见的应用场景我们需要1000个不同的用户进行登录,这里就可以用到csv格式的文件来做一个简单的数据参数化。**
注意,这里的逗号和上面json数据文件里的逗号都是半角的。创建csv数据文件的方法和创建json的一样,新建一个txt文件,写入数据即可,然后修改后缀。如果无法看到本身的后缀可以参照下图;最后在文件里写入你想要的数据即可。![](https://img-blog.csdnimg.cn/9da927eb90a3457da570dfe51e30fe20.png)
2.4.3Postman关联的使用
在接口的层面来说模块与模块之间有依赖关系(或者说是接口和接口之间存在依赖关系),也就是需要借助postman的关联技术来实现。**最常见的就是 登录接口 返回的 令牌数据,被添加到其他的接口依赖,比如商城里的订单,或者人力资源管理系统里的员工管理等模块接口都是需要登录后才能再进行下一步的操作。**
上述的这个过程其实就是一个业务流程最小的一部分,那么这个实现步骤的原理是什么呢?假定:接口B产生的数据,被 接口A 依赖
1.发送 接口B 请求,获取响应数据。
2.将 响应数据,**放入公共容器(全局变量,环境变量)**中
3.接口A从 公共容器中,提取数据,发送请求。
在这里,全局变量的意思:就是postman中都可以使用的变量。不需要 单独创建环境。
环境变量的意思:在 特定的环境下,才能使用的变量。需要给此变量创建单独的环境。
在上图里知道了如何创建环境之后,我们就可以自己来创建想要的环境了:
我们看事物都要透过现象去看本质,怎么样才能将所需要的东西(响应数据)放到这个容器然后再按需取出来,也是依然三个步骤,利用核心的代码来解释(不是使用)
1.提取响应数据
var jsonData = pm.response.json();
//可以很明显的看的出来这句话就是先前在断言脚本里当中那句提取的脚本让jsonData变量存储pm实例响应方法response.json()的内容
2.设置环境变量
pm.enviroment.set("var_name",value)
pm.globals.set("全局变量名",全局变量值) //环境变量,记得是globals
3.引用环境变量
从请求数据(URL,请求头Headers,请求体body)中提取 全局、环境变量 数据
{{全局变量名}}/{{环境变量名}} ex: {{city}}
其实这里有一个用代码来进行引用的,但是局限某个标签因此我们不适用这个方式。
案例一:
**使用postman关联,实现上面查询天气接口,获取返回结果中的城市名称,然后使用百度搜索接口,把获取到的城市名称作为请求参数。**
拿到这样一个接口,根据流程我们首先要知道关联和被关联接口的请求行的内容:http://www.weather.com.cn/data/sk/101010100.html
上面的是获取北京天气的接口,下面的是百度搜索接口的请求行及请求参数名http://www.baidu.com/?wd=
分析完了,就可以直接在我们的Tests里添加上面说的核心脚本代码:
var jsonData = pm.response.json(); // 获取响应结果
var city = jsonData.weatherinfo.city; //从响应结果中,提取到 城市名
pm.globals.set("glb_city",city) //将城市名保存到 全局变量
我们在写完这几行脚本后,按下发送会发现好像并没有什么变化,但是这时候我们其实已经设置出了一个全局变量了。我们可以**在右上方的小眼睛里查看一下具体的设置效果**。也就是我们设置好的变量名和变量值。
**到这里,并没有结束**!还有依赖的接口去提取被依赖接口响应数据当中的数据来作为请求参数的部分没有完成,就是刚刚所说的**全局变量的引用---也就是依赖的接口中的请求参数就是全局变量值。**
一样的,我们这里其实就是很简单的在Params(参数)里填写我们请求参数值的即可。因为给出的请求参数名已经有了是wd。最后效果如下图就是正确的。![](https://img-blog.csdnimg.cn/34c0c2669c254c5784974dc8cdff254f.png)
案例二:
**使用postman 关联技术,实现在商城项目中去查看购物车,这就需要查看购物车的接口去依赖登录的接口。**
我使用的是网上找到的资源 轻商城(当然感兴趣的也可以去找开源商城项目-tpshop,我看不少人用这个),避免了说因为没有实际项目大家想去学习又无法实践的情况。**不过,现在的资源很多真的都是已经是现成的了,大家要多去留意就能找到很好的学习和实践的机会。**
这样的商城项目也是可以在我们后期做性能测试的一个实践项目,商城项目是最需要考验到并发数和压力测试的项目了,不仅是因为其具有大量用户基数,在支付这个重要的模块当中也需要进行大量金额数据或者其他订单数据的模拟,因此在一开始就来以这个开源的项目作为一个好的出发点,也是我们后续不断进行测试技术手段拔高的一个方法。
注:这种找到的资源的方法,如果觉得不方便的话可以找我要一下,因为软件比较大,它的环境搭建是需要下载一个vm虚拟机的,然后已经是做好的一个Centos-litemall.zip压缩包,在windows环境下可以直接进行解压然后放到虚拟机当中就可以,对应的还是在linux系统底下进行一个ifconfig查看当前的ip,然后在我们的浏览器地址里输入即可。我也会提供给你简单的一个api文档,当然看我下面的演示和截图也是可以看得懂我们这个案例二对于这样有依赖的接口是如何提取一个令牌或者说是授权的。
基础环境搭建步骤:
1.先查看我们的这个虚拟环境下的一个ip,当然也可以直接使用域名登录进去就是了。具体的操作方法就不细说了,也就是打开终端输入指令就可以。不过这个ip可能有时会变化的,不一定是固定的,大家如果出现说浏览有问题的时候可以再来刷一遍指令。
然后,记得我们的端口号是8082。当然要是想按上面说的输入域名,也有这么一个好的方法,就是修改电脑的主机配置文件,一般目录放在C:\windows\System32\drivers\etc里的host,然后我们直接按下图的流程来设置域名解析。
下面就是在浏览器的输入框里输入资源路径:
看到标题,我们是需要先进行登录,比如我们直接点击上面的购物车选项,必然会提醒你需要进行登录,那么会跳到下面的这样一个窗口:
我们按照提示去输入测试的用户和密码,当然!作为一个合格的软件测试,我们最好是能够对每一个事件的请求都进行抓包分析,这样即使在没有开发提供的api文档下你也能通过简单的数据分析看到目前的http请求响应回来了哪些数据!看下图,就是我们使用f12的工具抓取到的具体的一个信息:能够知道具体的请求行和请求头的数据。![](https://img-blog.csdnimg.cn/8a2982359626481cbbc8aaeb3d4310f3.png)
我们这时还是开着这个f12的开发者工具来进行抓包,同时我们可以点击查看购物车了,再看看抓取到的报文返回的是什么
我们同样找到了这么一个查询的http请求的信息,那么接下来就好办了,我们还是使用我们的postman,先来建立对应的这两个接口:登录接口,查看购物车接口。
首先是对登录接口进行请求的发送,然后会得到下面这张截图,里面也包含了我们每一部的用意。![](https://img-blog.csdnimg.cn/11dabadcef17469c983f4c35e31bb857.png)
然后先不急着重温,我们可以来**看是哪个部分需要用到这个token引用的值。**![](https://img-blog.csdnimg.cn/ff26115cddbe49c09f0e3709bf080d9e.png)
很明显,请求头当中需要这么一个取值的过程,那么**我们接下来的步骤也和先前一样写一小段提取相关的脚本创建一个全局的变量,就叫它Token好了。**大家肯定觉得很烦,为什么都用工具了我们还要在这写代码= =,没办法postman它就是这样,不爽可以去用jmeter啊哈哈哈哈,提一嘴jmeter确实更好用像这样的提取响应数据里的部分需要的数据可以用例如json提取器或正则表达式、xpath提取这几种元件方式就能够很好的提取出变量了。
这时候基本已经要大功告成了,还记得我们是在哪里引用的吗?没错就是上面抓包分析截图提到过的请求头当中!我们在请求头当中来写我们的请求头即可。
我们先来看看 在没有令牌下的响应情况:很明显返回告诉我们需要登录!!
加上令牌之后,依赖于上一个登录接口所需要的响应数据作为请求头,迎刃而解这个问题。
注:放了这么多张图,一步步傻瓜式的教学甚至包含了抓包自己分析的一个简单过程,其实也是**希望通过这样的一个思路能够让大家更清楚每个http请求的原理,不只是想说我们学会了postman的什么什么用法,而是明白postman这样用是基于http协议的原理。不能只停留在工具的使用上,我们不是对工具的硬性的学习,也要学会变通,知道说为什么要添加这些个数据或者变量。**
** 2.4.4 Postman参数化**
什么是参数化:
将 测试数据,组织到 数据文件中,通过脚本的反复迭代,使用不同的数据,达到测试不同用例的目标。
应用场景:
一般在测试同一个接口的 不同测试点时,只有测试数据不同。才考虑 使用参数化。
常见的数据文件简介:
csv数据文件和json文件,其实上面2.4.2提到了这两种文件的区别,我就不详细展开,直接说他们各自的不足和应用场景即可。
**csv不足**:
1.不能测试bool类型,因为postman读取到csv后,将所有非书画纸类型数据,自动添加""变为字符串
2.不能存储复杂数据类型(元组,列表,字典)--这里是python里面的定义
3.应用场景:数据量较大,数据组织格式简单 例如:登录模块
例如:
username,password,message
13012345678,123456,登陆成功
12312345678,error,密码错误
31212345678,123456,账号不存在
** json不足:**
1.存储数据量,json文件要远大于csv文件。
2.应用场景:数据量较少,数据组织格式复杂。需要进行 参数测试!
例如:
[
{"username":"13012345678","password":"123456","message":"登陆成功"},
{"username":"13012345678","password":"error","message":"密码错误"},
{"username":"31212345678","password":"123456","message":"账号不存在"}
]
当然了,这个看起来实际上还是和真正的json格式有点区别,比如有缩进啥的会更美观。我们使用一个网站 json.cn , 它能够很好地把我们写好的json格式的文件自动像编译器那样进行一个规范的调整如下图所示:
根据上面2.4.4和前面2.4.2的部分,我们自己成功的修改了文件后缀并且完成了想要的数据格式的文件后,我们就可以将它们导入到postman当中了
我们思考一下如何来读取postman当中的数据文件里的数据呢?可以想到和刚刚依赖的方法一样,**参数化参数化那肯定是需要引用参数啊!!我们引用参数是怎么引用的呢?没错,就是用{{param}}来进行引用,比如{{字段名}},{{键名}}。**
那么除了这种方法(**对请求参数--请求行,请求头,请求体里进行引用**),还有一个是**在代码(Tests)中来进行数据文件中数据的使用,我们可以使用postman内置的 关键字 data,来 索引 字段名(CSV文件) 或 键名(JSON文件)。**
只有理论不实操肯定是不行的啊,下面就通过一个实际的案例来进行验证即可。
ex1:批量查询 手机号 所属的运营商,校验运营商数据正确性
接口:http://cx.shouji.360.cn/phonearea.php?number=13012345678
** **那么,我们就需要来分析一下我们怎么让它自动去写入每个我们想要验证的数据,首先我们看到接口:很明显在?后面的格式是xx=xx这样的一个形式,这不就是我们http请求里的请求参数吗?是不是感觉思路很快就来了,在params里直接添加一个number,然后值就定义一个类似环境变量的变量名即可,然后通过我们先前tests里面的代码脚本去写出来想要的这个环境变量,比如看下图,我们查询返回会得到某个响应数据例如:data.sp 这个就是运营商为电信的手机号。
很显然,我们是需要填写我们所要查的手机号然后对比验证我们是否返回的响应值是我们想要的,就是这么简单的一个逻辑,这是不是就是预期结果和实际结果的对比?那这不就是我们前面说的一阶逻辑的断言脚本吗?是吧,我们又绕回原先的知识点了!
还是一样,打开我们的Tests 点击我们最常见的那三个断言!我们这时选择的肯定是json响应数据当中我们想要的部分 ,然后修改个用例标题“不同手机号对应的运营商正确”
这里会看到我后面还有一个data.yunyingshang这就是我们csv数据文件当中的这个字段名:![](https://img-blog.csdnimg.cn/da8ee7c1b3e74435b0f9dbdf8357fd07.png)
通过这样的断言,都是我们熟悉的也是自动生成的。那么我们只需要去引用我们的参数就可以了,也就是把请求参数的值用我们的变量名来替代即可,如下图所示
这时候我们不会再使用send来进行请求的发送了,因为我们需要执行多次,这个send只是单次的点击,我们需要使用Runner也就是用例集这样的能够循环执行的过程。
最后结果就会像下面这个图里一样,能够清晰的看到我们想要的每条用例的结果,这样我们的参数化是不是也很像我们想要的简单自动化的测试。**我们最常见的使用场景就是这样输入简单的多组数据来模拟同一个接口不同情境下的测试用例。**
2.5 接口测试报告
我们知道一份好的报告能够很直观的体现出结果,那么我们是否有工具能够将我们的接口测试的报告进行一个可视化呢?有的,**postman就存在这样现成的插件newman能够提供给我们可视化接口测试报告的方法。**
2.5.1环境搭建
**1.在安装newman之前,我们必须安装好node.js**,啥是node.js?粗俗的理解**它就是一个极度适配JavaScript的平台,能够让JavaScript运行在服务端的一个开发平台。**
可以自己先检查一下,是否在电脑里有安装过node.js,测试的方法就是打开电脑里的cmd命令行,然后输入npm -v,版本多少没有关系。
如果没有的话就直接去下载就好了,下载 | Node.js 地址在这。
**2.在我们安装完node.js后,我们就可以开始在线安装newman**了,指令就是 npm install -g newman
注意:最好使用管理员权限进入cmd,当然安装失败也是正常的,最好保证网速的情况下避开高峰期(比如夜深人静的时候),失败了要勇于面对失败,装个十几次也是很正常的,btw我用5g网络热点一次成功哈哈哈。
然后自己再进行一下装完后的验证,输入 newman -v 就可以查看到版本号了。
**3.最后一步,安装newman-reporter-htmlextra**
安装命令:npm install -g newman-reporter-htmlextra,这里同样也是用管理员权限。
一般newman安装成功,这个也是能安装成功的。
2.5.2导出用例集和环境变量
对用例集操作,直接看下图
导出后的名字也不建议修改,按照自动命名即可
注意!如果你的里面包含了测试环境,也一定要导出你的测试环境,比如使用了环境变量像上面的全局变量这样的,就要如下图导出环境变量的文件
2.5.3newman生成测试报告
完整命令如下:
newman run 用例集文件.json -e 环境文件.json -d 数据文件.json/.csv -r htmlextra --reporter-htmlextra-eport 测试报告名.html
注意:
** -e 和 -d 是 非必需的。如果没有环境就不用-e ,如果没有数据文件不做参数化就不用-d**
并且,这些文件都需要在同一个目录底下!!!!简单的方法就是,在地址栏里输入cmd即可进入当前目录下的一个cmd命令操作,也是最便捷的!
最后生成的网页版本的可视化的测试报告就如下图所示:
3.总结
这一篇博文长篇大约有2w字左右,可能看起来会很长,但是通过这个博文基本能够半只脚迈入对接口测试的理解,不过还是那句话只有理论支持是在实践里是无法做好的,即使再好的理解能力也需要稍微动手,起码要下载一个工具来看看吧。好了,再来回顾一下,博客讲了哪些知识点。
3.1回顾
首先,我们对http协议里的http请求和http响应做了个细致一点的了解;然后根据我们的测试流程,分别讲了接口测试所需要文档分析,接口用例设计,接口用例执行(使用postman工具),如何用postman自带的newman插件输出可视化的测试报告;最后也是最重要的一点就是讲解通过工具来对接口进行测试。
在讲解postman工具使用的过程中伴随实例的演示,也对使用频率最高的几个功能进行了解析
1.基础使用:能够对get或者post这两个最常用的方法来实现正确的请求数据发出后能接收返回正常的响应数据。
2.断言使用:利用3个常用断言的脚本来判断我们响应数据内容是否为我们所要的预期结果,通过断言也接触到了脚本里的一些键或者是字段的定义
3.参数化使用:学习了两种常见的参数化数据文件类型,并且能够将文件中的数据循环作为多条用例执行的动作去避免反复的操作,结合断言使用能够执行较完整的接口用例。
4.依赖使用:上述的方法用在单功能模块接口,如果需要关联其他的接口,例如登录后才能执行具体的功能操作实现业务流程功能的实现,这样就需要将另外一个接口的响应数据提取出来到我们的环境变量或者全局变量当中去,然后用依赖的形式再把它引用到新的请求数据当中(不限于请求行或是请求头请求体中)。常见的主要是请求头中的token或者请求行中的路径参数target。
5.可视化结果:postman自带的newman插件,在cmd后台输入对应的完整命令就会在目录下生成报告了。能够避免编写测试报告,通过生成本地web页面的一份可视化测试报告提高工作效率。
3.2眺望
当然了,接口测试肯定还有更多的有逼格的测试手段,首先呢,我们依然是可以使用工具,我们可以利用一直提到过的jmeter,它有更丰富的第三方包也就是有更多的便捷的功能供测试人员使用,同时jmeter也能完成一部分性能测试的任务,可以压力测试也可以稳定性挂测。
如果用不惯工具,我们也能够使用代码去实现接口测试,如下图就是简单的用python里的requests库去做的接口测试,内容很简单就是使用get请求去对百度进行一个页面的访问。![](https://img-blog.csdnimg.cn/9c539632e2464235ba86d2dd1c9f26f2.png)
大家不要看着这一长串很烦,其实它就是我们前面讲的html文本显示,可以去回顾一下还是容易理解的。之后我也会继续再写一篇用jmeter来做接口测试的用法以及python requests用到的接口测试方法。其实他们的原理都是类似的,只是不同工具所展现的界面不一样而已。**工具自始至终都是用来协助的,最重要的还是我们使用者要懂其中的原理。**
版权归原作者 Deric_ 所有, 如有侵权,请联系我们删除。