基于工具Poatman的接口自动化基础应用以及接口关联
一、什么是接口?
硬件接口:USB接口,投影仪接口,鼠标键盘接口
软件接口:称为API,主要使用于数据交互
软件接口分类:
内部接口:开发人员开发一个系统,此系统提供了一些接口给本系统使用。
特点:对安全要求不高,外界访问不到。只需要测正例
外部接口:
1.系统对外提供的接口:这种接口外部的用户是可以接触到,对安全性要求很高。
2.系统调用外部的接口:开发的电商系统需要支付宝和微信支付。只需要测正例。
二、为什么需要做接口测试
集成阶段
1.前后端分离,子系统分离
2.基于安全考虑
3.测试前移
三、目前市面上的接口架构设计以及基于的协议
(1)基于SOAP的接口架构,它是一种轻量级的简单的基于XML的协议规范。基于webservice协议,地址是以?wsdl结尾。是一种比较老的技术。
(2)基于RPC的接口架构,它是一种远程调用,调用服务器的服务接口就和调用本地一样。
1.dubbo协议,阿里的rpc框架。地址是以dubbo://开头的,适合传输高并发数据量少的数据。
2.基于springcloud的微服务
3.thrift,rmi,hessian
(3)基于RestFul的接口架构,主流,默认是使用的http协议。它默认使用json传输数据。
它有一种规则(80%以上):
对于同样的一个接口地址:如http://127.0.0.1/user,使用不同的请求方式得到的结果不一样。
get(查询用户),post(增加用户),put(修改用户),delete(删除用户)
四、http协议详解
(1)什么是http协议?
http协议是超文本传输协议,主要用于浏览器和服务器之间交互数据,交互分为请求和响应两部分。
请求:请求行,请求头,请求正文数据。
响应:相应行,响应头,响应正文数据。
响应码:1xx信息,2xx请求成功,3xx重定向,4xx客户端错误,5xx服务器错误
请求:
请求行:POST /phpwind/index.php?m=u&c=login&a=dorun HTTP/1.1
请求头:
Host: 47.107.116.139
Connection: keep-alive
Content-Length: 112
Accept: application/json, text/javascript, /; q=0.01(客户端接收的数据类型)
X-Requested-With: XMLHttpRequest(ajax异步请求(不需要刷新),高速上有多条道,多线程)
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114
Safari/537.36(客户端类型)
Content-Type: application/x-www-form-urlencoded; charset=UTF-8(内容的格式)
Origin: LNMP一键安装包 by Licess
Referer: 登录 - phpwind 9.0 - Powered by phpwind
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie:csrf_token=78e0caa2743c89fa;wNq_visitor=Nsb6UFT9aEsPxBlZw0XRqvIIZVOHaYgnTMt9rdP0EoY%3D;
wNq_lastvisit=697%091621428405%09%2Fphpwind%2Findex.php%3Fm%3Du%26c%3Dlogin%26a%3Dcheckname(Cookie 信息)
Cookie的原理:(清空本地的Cookie数据,然后按Shitf+F5去缓存刷新)
Cookie它不是缓存,它是保存在客户端的一小段的文本信息,格式是dict格式,
原理:当客户端第一次访问服务器的时候,那么服务器就会生成Cookie信息,这个Cookie信息会通过响应头里面的Set-Cookie传输 到客户端。从第2-N次请求,只要访问当前的域名和路径,那么客户端就会在请求头的Cookie里面自动的带上客户端的Cookie信息。
请求正文数据:
五、接口返回的数据格式
1.json格式
JSON是一种数据格式,它由键值对和列表构成。
接口开发的潜规则:{error_code:错误码,message:错误码的中文说明,data[]}
2.html格式
3.XML格式
六、接口测试的流程和方案
1.拿到api接口文档(规范:swagger,showdoc;不规范:word文档;没有:抓包或录制),熟练接口业务,接口地址,接口鉴权,接口入参,接口出参,错误码。
头疼的面试题:在你们的这个项目(App)中,你测了哪些接口?凡是有数据交互的地方就有接口。
例如:查询支付宝余额接口。查询芝麻分接口
2.编写接口测试计划和方案(接口怎么测)
思路:
正例:输入正常的入参,接口成功返回。
反例:
鉴权反例:鉴权码为空,错误的鉴权码,鉴权码过期。。。
参数反例:参数为空,参数类型异常,参数长度异常,错误码异常。。。
其他场景:接口黑名单,接口调用次数,接口分页(0,1,中间页,最后一页),根据业务来定
3.编写接口测试用例
4.使用接口测试用例执行接口测试
5.输出接口测试报告(HTML格式)
七、目前市场上的接口测试工具
Postman+newman+git+jenkins实现接口自动化。
newman是专为poatman而生,主要用于和jenkins持续集成
Jmeter+Ant+Git+Jenkins实现接口自动化
Ant是Jmeter的插件,主要用于和Jenkins持续集成
其他工具:
soupui.apipost,fiddler.charles
八、微信公众号的测试接口(去公众号获取)
appID:wx1eb473c6c8fa3809
appsecret:*****************************
九、Postman的安装和界面介绍
mock server服务器。桩程序。(前后端分离,前端已经开发好了,后端的接口没有开发好,那么我们测试就可以自定义一个Mock Server,前端访问Mock的接口去测试)
十、Postman发送Get以及Post请求
请求部分:
Params:get请求传参。
Authorization:鉴权
Headers:请求头
Body:post请求传参
form-data:即可以传键值对,也可以传文件。
x-www-from-urlencoded:只能传键值对
raw:传json,xml,javascript,txt.html
binary:把文件转化成二进制传参。
Pre-requests Script:接口请求之前的脚本。
Tests:接口请求之后的脚本。
Settings:设置。
Cookie:是Postman自动的管理Cookie信息的按钮。
响应部分:
Body:响应的数据
Pretty:可以以json,xml,html,txt查看响应数据。
Raw:以文本的格式查看响应数据
Preview:以网页的形式查看响应数据
Cookies:响应的Cookie信息
Headers:响应头信息
Test Results:查看断言结果
状态码:200
状态信息:OK
接口数据返回耗时:182MS
接口返回的数据量:343个字节。
面试题:Get请求和Post请求有什么区别?
1.get请求是获取数据,而post请求一般都是提交数据。
2.post请求比get安全。
3.本质的区别是:传输的方式不一样,get在url的后面以?的方式传参,多个参数之间用&分隔。post是通过body表单传参。
精通Postman接口测试之接口关联、动态参数、断言以及Poatman+Newman+Jenkins持续集成
一、 接口关联,接口依赖
下一个接口的参数是使用的上一个接口的返回值
接口测试,接口自动化。
1.JSON提取器(都是从返回值里面提取)
1 //javascript脚本,var定义变量
2 //打印responseBody返回值
3 console.log(responseBody)
4 //使用json提取器把responseBody返回值转化成一个字典。
5 var jd = JSON.parse(responseBody)
6 //提取access_token,并且设置为全局变量(就是在任何接口请求都可以访问的变量)
7 pm.globals.set("access_token",jd.access_token);
取得全局变量:{{access_token}}
2.正则表达式提取器(都是从返回值里面提取)
1 var token = responseBody.match(new RegExp('"access_token":"(.*?)"'));
2 pm.globals.set("access_token",token[1]);
3.从响应头里面中去提取
1 //从响应头里面提取变量
2 var types = postman.getResponseHeader("Content‐Type")
3 console.log(types)
4.从Cookie里面中去提取
1 //从Cookie里面提取变量
2 var csrf_token = postman.getResponseCookie('csrf_token');
3 console.log(csrf_token.value)
二、Postman的动态参数
接口测试中常常会出现接口的参数不能写死,必须使用随机数来实现。
1.内置的动态参数
{{$timestamp}} 时间戳
{{$randomInt}} 随机的0-1000的整数
{{$guid}} 随机的很长的字符串
2.自定义动态参数(重点)
1 //自定义的时间戳
2 var times = Date.now();
3 pm.globals.set("times",times);
4 //让接口请求停留3秒(3秒灌水机制),time.sleep(3)
5 const sleep = (milliseconds) => {
6 const start = Date.now();
7 while (Date.now() <= start + milliseconds) {}
8 };
9 sleep(3000);
三、Postman的全局变量和环境变量
全局变量:就是在所有接口请求里面都可以访问的变量
环境变量:就是全局变量。(开发环境,测试环境,线上环境)
四、Postman的断言
//断言返回吗为200
//断言返回结果中包含指定的字符串
//断言并检查返回的JSON数据
//断言返回的值等于一个字符串
//断言响应头包含Content-type
//断言响应时间少于200M
1 //断言返回吗为200
2 pm.test("Status code is 200", function () {
3 pm.response.to.have.status(200);
4 });
5 //断言返回结果中包含指定的字符串
6 pm.test("Body matches string", function () {
7 pm.expect(pm.response.text()).to.include("string_you_want_to_search");
8 });
9 //断言并检查返回的JSON数据
10 pm.test("Your test name", function () {
11 var jsonData = pm.response.json();
12 pm.expect(jsonData.value).to.eql(100);
13 });
14 //断言返回的值等于一个字符串
15 pm.test("Body is correct", function () {
16 pm.response.to.have.body("response_body_string");
17 });
18 //断言响应头包含Content‐type
19 pm.test("Content‐Type is present", function () {
20 pm.response.to.have.header("Content‐Type");
21 });
22 //断言响应时间少于200MS
23 pm.test("Response time is less than 200ms", function () {
24 pm.expect(pm.response.responseTime).to.be.below(200);
25 });
特别注意:
1.postman内置的动态参数无法做断言。所以必须使用自定义的动态参数。
2.在tests里面不能使用{{}}的方法取全局变量,必须使用以下方式:
pm.globals.get("times1")
globals['times1']
globals.times1
五、必须带请求头的接口如何测试
六、Postman+newman+jenkins实现自动生成报告并持续集成
Postman是为接口测试而生
Newman是为Postman而生
一、安装
1.安装Node.js
官网下载
验证:打开cmd,输入node后出现> ,说明安装成功
2.安装npm
打开cmd输入:npm install --global --production windows-build-tools
等待安装完成即可
3.安装newman
打开cmd输入:npm install -g newman
验证:输入newman -v,出现版本信息即为安装成功
二、导出postman的测试用例,环境变量,全局变量
newman run "测试用例文件地址" -e "环境变量文件地址" -g "全局变量文件地址" -r cli,html,json,junit --reporter-html-export "报告输出位置"
-e 环境变量
-g 全局变量
-r cli,html,json,junit --reporter-html-export 测试报告输出的路径
三、和jenkins持续集成
启动:在war包下执行命令:java -jar jenkins.war --httpPort=8080
1.构建:执行window批处理命令
2.构建后:Publish HTML Reports
精通Postamn接口测试之接口鉴权、接口Mock、接口加解密以及接口签名Sign
一、接口鉴权(鉴定是否有访问接口的权限)
(1)cookie、session、token鉴权
cookie鉴权:
cookie它是服务器产生的,保存在浏览器,主要是因为http协议无连接,无状态。(超市:没有会员卡,cookie:会员卡)
cookie通过键值对的方式来保护记录。原理:第一次访问服务器的时候,那么服务器就会产生cookie并且在响应头的set-cookie里面发送给浏览器,浏览器保存,在第2-N次请求时会带上cookie信息。
cookie一般包括信息:name,value,domain.path,expries,size。
回话级cookie和持久化cookie。
session鉴权:
session它是服务器产生的,保存在副武器的内存。它可以通过cookie来传参sessionid。原理:当你登录的时侯,那么服务器会生成session,它通过cookie把sessionid传给客户端,然后在后面所有的请求里面都会自动的带上sessionid。然后和服务器的内存中的sessionid对比以判断是否是同一个客户端。保存在服务器的内存里面的session的失效时间为30分钟。
sessionid可以隐藏域,也可以url或者是cookie传递。
token鉴权
token是服务器产生的,保存在服务器的文件或数据库(硬盘),一般情况下接口测试通过一个专门的获取token的接口或者是登录接口来获取token,获取后每次请求其他接口都必须带上token鉴权。
面试题:cookie、session、token的相同点和不同点?
相同点:都是在服务器产生的,都用于鉴权。只是保存在不同的地方。
不同点:cookie保存在客户端,所以不安全,一般情况下用cookie保存一些非重要的数据,而通过session去保存一些重要的数据,session是保存在服务器的内存当中,而token是独立的鉴权,它和session和cookie无关。
(2)Postman鉴权
bearer token鉴权:就是发送一个鉴权码(令牌)。
basic Auth鉴权:通过用户名和密码实现鉴权。
二、接口Mock Server
mock测试就是测试过程中,对于一些不容易创建或者是不容易获取的比较复杂的对象,用一个模拟的对象去代替。
mock一把是为了解决单元之间的耦合依赖关系。(桩服务)
比如:工作中前后端分离,前端已经开发好了,但是后端没有开发好。
三、接口的加解密
接口加密:接口测试当中把传输的数据加密成密文(01010111011010)再传输。
接口解密:获取密文后,把密文还原成原始数据。
1.目前市场上的加密方式
对称式加密(私钥加密):DES, AES, Base64
非对称式加密(双钥加密):RAS(公钥《公开》和私钥《保密》)
只加密不解密:MD5, SHA1 , SHA3.....
可用网址:在线JSON校验格式化工具(Be JSON)
2.Postman实现解密接口(可遇不可求)
需自定义函数来实现
四、接口签名Sign(接口鉴权的一种)
1.什么是接口签名?
接口签名就是使用appid,appsecret,nonce(流水号),timestamp,以及其他的各种参数按照一定的规则(ASCII排序)组成用来识别你的账号有没有访问api接口的权限的字符串,组成之后在进行加密,这个经过加密之后的字符串就是sign签名。
appid和appsec在线下针对不同的接口调用方法提供的。
流水号nonce,订单号一般是一串10位以上的随机一组数字或者随机的一组字符串。数字+字符串(guid)。
timestamp时间戳,一般10分钟之内有效。
2.为什么要做接口签名?(大大的提高接口安全性)
(1)防止接口鉴权码泄露,接口被伪装攻击(签名,只需要提供签名不需要鉴权码)
(2)防止接口数据被篡改(原理:签名针对的是所有的请求数据,只要有一个数字被改动了,那么sign就变了,就会请求失败)
(3)防止接口被重复提交,nonce是唯一的,并且只有10分钟之内有效。
3.接口签名的规则
接口签名的规则有很多,每个公司不一样,但是大同小异(80%以上相似)。
举例:
(1)获取到所有参数包括params和body,把所有的参数的key按照ascii码升序排列。
(2)把参数按照key=value的方式组合,多个参数用&分开。
(3)用申请到的appid和appsecret拼接到参数的最前面。
(4)把订单号和时间戳拼接到参数的最后面
(5)把上述字符串通过MD5加密。加密之后大写。形成sign
(6)然后把sign放在url或者请求头(一般都放请求头)或请求体里面发送给服务器做鉴权。
var appid = "test";
var appsecret = "123";
console.log(appid);
console.log(appsecret)
var nonce = getnonce(1000000000,9999999999);
console.log(nonce);
var timestamp = new Date().getTime();
console.log(timestamp);
var params = pm.request.url.query.members;
console.log(JSON.stringify(params));
var body = request.data;
console.log(JSON.stringify(body));
for(var i=0;i<params.length;i++){body[params[i].key] = params[i].value;
}
console.log(JSON.stringify(body));
var body_args = objectsort(body)
console.log(JSON.stringify(body_args));
var new_string = "";
for(var key in body_args){new_string += key + "=" + body_args[key] + "&";
}
console.log(JSON.stringify(new_string));
new_string = "appid=" + appid+"&"+"appsecret"+appsecret+"&"+new_string+"nonce="+nonce+"&"+"timestamp="+timestamp;
console.log(JSON.stringify(new_string));
var sign = CryptoJS.MD5(new_string).toString().toUpperCase();
console.log("sign="+sign);
pm.globals.set("sign", sign);
//----------------------------------------------------
//把对象的key升序排列
function objectsort(obj){var new_key = Object.keys(obj).sort();console.log(new_key);var arr = {};for(var i=0;i<new_key.length;i++){arr[new_key[i]] = obj[new_key[i]];}return arr;
}
//获取任意长度的随机数字
function getnonce(min,max){return Math.floor(Math.random() * (max-min + 1)) + min;
}