本篇博客
1 RESTful
2 HTTP协议
3 如何开展接口测试
4 正式开展测试
什么是接口测试?
接口测试:是测试系统组件间接口的一种测试方法
接口测试的重点:检查数据的交换,数据传递的正确性,以及接口间的逻辑依赖关系
接口测试的意义:在软件开发的同时实现并行测试,减少页面层测试的深度,缩短整个项目的测试周期
接口分类:系统内部接口和系统外部接口
系统内部接口:模块间的相互调用
系统外部接口:软件接口和硬件接口
软件接口:服务器接口和外部接口
服务器接口:是浏览器与服务器的接口,通过http协议来实现浏览器和服务器间的数据传递
外部接口:外部接口常见的典型例子就是通过第三方登录、第三方支付等,通过调用第三方接口并返回当前的系统
目前比较流行的接口测试就是软件接口的测试。
接口测试:实际上我们做接口测试,还是“输入—处理—输出”这样的模式。用户输入一串数据,然后让这个接口或者让这个后台功能来处理,然后检查输出结果跟期望是否一致。
本质是基于某种协议,发送一个Request请求给服务器,然后服务器返回一个Response响应数据,然后对响应数据进行分析,判断是否与我们预期的返回一致,从而验证功能是否正确,这就是接口测试。
那么客户端是如何向服务器发送请求的呢?
在这里我们先来介绍一下网站架构的设计风格
随着互联网的不断发展,网站设计风格逐渐统一于RESTful架构风格。
REST最大的几个特点为:资源、统一接口、URI和无状态。
1 RESTful
RESTful 特点:
- 资源
- 统一接口
- URI:统一资源定位符
- 无状态
1.资源
所谓"资源",就是网络上的一个实体,或者说是网络上的一个具体信息。它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的实在。资源总要通过某种载体反应其内容,文本可以用txt格式表现,也可以用HTML格式、XML格式表现,甚至可以采用二进制格式;图片可以用JPG格式表现,也可以用PNG格式表现;JSON是现在最常用的资源表示格式。
2.统一接口
RESTful架构风格规定,数据的元操作,即CRUD(create, read, update和delete,即数据的增删查改)操作,分别对应于HTTP方法:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源,这样就统一了数据操作的接口,仅通过HTTP方法,就可以完成对数据的所有增删查改工作。也就是说处理资源通过http方法GET/POST/PUT/DELETE实现
即:
- GET(SELECT):从服务器取出资源(一项或多项)。
- POST(CREATE):在服务器新建一个资源。
- PUT(UPDATE):在服务器更新资源(客户端提供完整资源数据)。
- DELETE(DELETE):从服务器删除资源。
3.URI
可以用一个URI(统一资源定位符)指向资源,即每个URI都对应一个特定的资源。要获取这个资源,访问它的URI就可以,因此URI就成了每一个资源的地址或识别符。
4.无状态
所谓无状态的,即所有的资源,都可以通过URI定位,而且这个定位与其他资源无关,也不会因为其他资源的变化而改变。
综上所述总结如下:
1. 在RESTful中一切都认为是资源,且每个资源都有对应的URI标识
2. 客户端通过GET/POST/PUT/DELETE等http方法对资源进行操作,即客户端通过http协议与服务器进行通信,并获取资源信息
2 HTTP协议
http(超文本传输协议)是一个基于请求与响应模式的、无状态的、应用层的协议,常基于TCP的连接方式,HTTP1.1版本中给出一种持续连接的机制,绝大多数的Web开发,都是构建在HTTP协议之上的Web应用。
HTTP协议的主要特点可概括如下:
1.支持客户/服务器模式。
2.简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、HEAD、POST。每种方法规定了客户与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的程序规模小,因
而通信速度很快。
3.灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记。
4.无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
5.无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需
要先前信息时它的应答就较快。
2.1 URL篇
一个URL就是一个接口:接口大致会分为一下几个部分:
1.请求协议:
- http — 普通的http请求
- https — 加密的http请求,传输数据更加安全
- ftp — 文件传输协议,主要用来传输文件
2.请求IP:就是指提供接口的系统所部署的服务器地址
3.请求端口:如果不填端口,默认80,否则需要填写端口号
4.接口路径:指系统提供的接口在什么位置
5.接口参数:参数在接口路径后,用“?”来表示路径地址完了,剩下的都是参数了,用“&”来区分参数个数,
格式(重点)
http://host[":"port][[abs_path]]
- http表示要通过HTTP协议来定位网络资源;
- host表示合法的Internet主机域名或者IP地址;
- port指定一个端口号,为空则使用缺省端口80;
- abs_path指定请求资源的URI;
如果URL中没有给出abs_path,那么当它作为请求URI时,必须以“/”的形式给出,通常这个工作浏览器自动帮我们完成。
例子:
1、输入:www.guet.edu.cn
浏览器自动转换成:http://www.guet.edu.cn/
2、http:192.168.0.116:8080/index.jsp
2.2 请求篇
1.请求篇包含:请求头和请求体
2.请求头的第一行非常的重要,包含请求方法(Request Method)和URL(Request URL)。这两个东西是非常核心的东西。
请求方法有GET方法,POST方法,需要知道他们之间的区别,当然区别最明显的就是GET请求没有请求体,而POST请求有请求体。
请求头里有很多项,每一项最好能知道是什么意思,并且要知道哪些项是比较核心的,其实核心的东西不多。一个是content-type,一个是cookies。
3.URL,相当于接口的入口。
备注:网上很多资料会把请求分为三部分,请求行、请求头和请求体。这里的请求头的第一行其实就是请求行了,下面的响应也是一样
请求体包括参数,一般我们在测试的时候会修改请求体里的东西。
懂了上面这些,就知道该如何组装HTTP请求了。
4.请求方法(所有方法全为大写)有多种,主要是GET和POST。
GET(SELECT):从服务器取出资源(一项或多项)。在做数据查询时,建议用GET方式,如:商品信息接口、搜索接口、博客访客接口...
POST(CREATE):在服务器新建一个资源。在做数据添加、修改时,建议用POST方式。如:上传图片接口、登录注册接口...
PUT(UPDATE):在服务器更新资源(客户端提供完整资源数据)。
DELETE(DELETE):从服务器删除资源。
误区:GET是从服务器上获取数据,POST是向服务器传送数据”(该说法有误)
解析:GET/POST都可以提交数据,GET请求也可以向服务器传递数据,POST请求也需要服务器返回数据
2.3 响应篇
在接收和解释请求消息后,服务器返回一个HTTP响应消息。
响应篇:包含响应头,响应体。响应头里的第一行有响应的状态码和状态信息。
面试时候一般会被问到:状态码有几类?一般是有五类,
状态码:1开头(请求正在处理),2开头(请求处理成功),3开头(重定向),4开头(客户端错误),5开头(服务器错误)。这五类分别代表什么需要记住。一般5开头的都是系统bug。
状态行格式:协议版本 状态码 状态原因
eg:HTTP/1.1 200 OK (CRLF)
常见状态代码、状态描述、说明:(这是重点!!!)
200 OK //客户端请求成功
400 Bad Request //客户端请求有语法错误,不能被服务器所理解
401 Unauthorized //请求未经授权,没有认证或者认证不正确。(一般在响应头部包含一个WWW-Authenticate来描述如何认证。)
403 Forbidden //客户端没有权限访问要求的资源。
404 Not Found //请求资源不存在,eg:输入了错误的URL
500 Internal Server Error //服务器错误
503 Server Unavailable //服务器当前不能处理客户端的请求(可能是临时超载或者是服务器进行维护),一段时间后可能恢复正常
2.4 消息报头
HTTP消息报头包括普通报头、请求报头、响应报头、实体报头。
每一个报头域都是由名字+“:”+空格+值组成,消息报头域的名字是大小写无关的。
- 普通报头
- 请求报头
- 响应报头
- 实体报头
- 组成:名字+":" +值
请求报头
请求报头允许客户端向服务器端传递请求的附加信息以及客户端自身的信息。
常用的请求报头
Authorization 请求认证(jwt) 认证失败状态码为401(未授权)
Host 记录了当前服务器地址,主用途的为了解析域名,使域名的解析成功 Host:www.guet.edu.cn
User-Agent 浏览器请求头
application 请求类型 请求类型,如json
2.5 请求正文
请求正文:
get:没有请求正文信息
post:请求正文与请求报头中间由空行隔开
2.6 响应实体
响应实体:与消息报头之间由空行隔开
3 如何开展接口测试
1.跟开发要接口文档
2.构造测试数据,编写测试用例
做测试:
要输入正确的键值,例如看边界,看结果
也要输入错误的键值,看错误的结果(一般文档有异常描述,不然不知道异常的结果对不对。)
对输出参数结果判断是否正确。
4 正式开展测试
4.1 需要安装第三方库requests
命令:打开cmd窗口--->输入pip install requests
4.2 get请求接口
1.导包
2.构造接口地址
3.构造请求参数
4.发送get请求
5.获取响应数据
案例:
import requests # 定义接口地址 url = "http://v.juhe.cn/weather/uni" para = {"key":"221ec2c9d854d2859310ea808cb760fd"} # para = {"key":"221ec2c9d854d2859310ea808cb760"} # 发送接口请求 r = requests.get(url,params=para) # 获取json数据 res = r.json() print(res) print(res["resultcode"]) print(res["error_code"])
4.3 post请求接口
1.导包
2.构造接口地址
3.构造请求参数
4.发送post请求
5.获取响应数据
案例:
import requests url ="http://v.juhe.cn/weather/ip" # para = {"ip":"58.215.185.154","key":"32d1b2ada7885afbb3a0a516d9298bfa"} para = {"ip":"58.215.185","key":"221ec2c9d854d2859310ea808cb760fd"} # 发送post请求 r = requests.post(url,data=para) # 获取json数据 res = r.json() print(res) print(res["reason"]) print(res["error_code"])
4.4 参数关联接口
参数关联:我们需要将一个请求的响应参数,作为另一个请求的入参。比如登录后的操作,第一步实现登录请求,然后将请求返回的token提取出来保存到一个变量中,后续请求作为入参使用
1.导包
2.构造接口地址
3.构造请求参数
4.发送接口请求
s = requests.session()
s.请求方法(url,参数数据)
5.使用正则匹配接口响应数据的内容
6.构造接口请求参数
7.发送接口请求
s.请求方法(url,参数数据)
8.打印结果
准备工作
1.首先把webtours服务器打开。
开始--所有程序---HP LoadRunner---Samples---Web----Start Web Server
2.获取ip地址。cmd------ipconfig
3.浏览器访问:http://192.168.197.1:1080/WebTours/
用户名:jojo,密码:bean
fiddle抓包,获取usersession。
小总结:
1.记住打开页面时url地址位置(前面序号)
2.登陆后,找到登陆的地址
3.usersession肯定是在登陆url前面的地址。
4.在登陆地址中需要找到请求参数,和响应结果。结果:WebTours是判断接口代码正确性的依据。
用fiddle抓包工具访问上面的网站
1.打开fiddle工具,
- 点击Filters(前面的勾选上)
- 再输入过滤网址:192.168.197.1; (网址输好后,也可以点击Filters下面的Actions中的Run Filterset now)
- 点击上面的ie浏览器
扩展:不想要过滤
Filters-------Use Filters(前面的勾去掉)------Actions(点击Run Filterset now)。
2.再打开的ie浏览器(浏览器是自动打开的,软件帮我们打的。)输入网址:http://192.168.197.1:1080/WebTours/。点击回车。
3.再fiddle抓包下面,输入:cls。清空上面的。
清空完的样子
4.刷新ie浏览器的网址,可以看下fiddle的记录。记住到2url都是打开网址的记录,这点很重要
再填写用户名,密码登陆。回车
5.看下fiddle工具抓到的url。
6.拷贝4url地址:http://192.168.197.1:1080/WebTours/login.pl(这个就是登陆地址。copy----Just Url)
7.登陆地址:4url中这里看到是post请求,说明请求参数是在请求体里。(4url-----Inspectors----Headers)
8.登陆地址:4url中----Inspectos-----TextView和WebForms。都可以查看请求参数的。后面代码会把下面的请求参数全部复制出来,不能有遗漏。
9.登陆地址:4url中,看响应部分,点击Raw,标题是"Web Tours"。这个很重要,是判断后面代码能否实现的依据。如果代码运行,返回的响应标题有"Web Tours",就说明代码正确实现。
10.usersession是变动的,每次都不一样。在左边部分搜索useression,ctrl+f:搜索
11.黄色的显示url里面有usersession的值。其中有个是在登陆4url之前有个3url就有usersession。需要查看这个3url的请求和响应。
12.这里查看3url,上面的请求里面没有usersession,下面的响应里搜到了usersession。
这里usersession是打开网站的时候,服务器给我们的响应数据,名为usersession,值是随机的。下次我们登陆的时候,把usersession的作为参数传给服务器。这就是参数关联。
下面是代码啦
获取usersession的值。这里访问打开网站的3url。(是登陆前,响应里有usersession的url。)
# 导包 import requests #获取usersession的地址 url1 = "http://192.168.197.1:1080/WebTours/nav.pl?in=home" r = requests.session() res = r.get(url1) print(res.text)
查看运行结果,有usersession。
总的代码
# 导包 import requests import re #获取usersession的地址 url1 = "http://192.168.197.1:1080/WebTours/nav.pl?in=home" r = requests.session() #为了和下一个接口建立相同的连接通道 res = r.get(url1) print(res.text) usersession = re.findall(r'name=userSession value=(.+?)>',res.text) print(usersession) #登陆地址 url2 = "http://192.168.197.1:1080/WebTours/login.pl" # 参数 para ={"userSession":usersession[0],"username":"jojo","password":"bean","login.x":"54","login.y":"11","login":"Login","JSFormSubmit":"off"} s = r.post(url2,data=para) print(s.text)
运行结果有:Web Tours。说明是正确的。
4.5 数据和代码分离
把数据放在excel里,使用第三方库:xlrd ,进行读取。
第一种方法安装xlrd:
pip install xlrd
第二种方法安装xlrd:
easy_install xlrd
Commonlib:读取数据的
Data:放数据的
unittest应用:测试文件
案例1:加法测试
Data-----data1.xlsx
数字前加单引号,数字变文本格式。
Commonlib------ReadExc.py
import xlrd class Read_Ex(): def read_excel(self): #打开excel表 # book = xlrd.open_workbook("../Data/data2.xlsx") book = xlrd.open_workbook("../Data/data1.xlsx") #找到sheet页 table = book.sheet_by_name("Sheet1") #获取总行数总列数 row_Num = table.nrows #获取总行数总列数 col_Num = table.ncols #获取总行数总列数 s =[] key =table.row_values(0)# 这是第一行数据,作为字典的key值 if row_Num <= 1: print("没数据") else: j = 1 for i in range(row_Num-1): # print(i) d ={} values = table.row_values(j) for x in range(col_Num): # print(values) d[key[x]]=values[x] j+=1 s.append(d) return s if __name__ == '__main__': r = Read_Ex() s=r.read_excel() print(s)
unittest应用-----加法测试.py
# 导包 import unittest import sys sys.path.append("..") from Commonlib.ReadExc import Read_Ex class Test_Add(unittest.TestCase): def setUp(self): print("开始") def tearDown(self): print("结束") def test01(self): r =Read_Ex() data = r.read_excel() for i in data: self.assertEqual(int(i['a'])+int(i['b']),int(i['c'])) # a = 1 # b = 1 # self.assertEqual(2,a+b) if __name__ == '__main__': unittest.main()
案例2:天气测试
Data-----data2.xlsx
Commonlib------ReadExc.py
import xlrd class Read_Ex(): def read_excel(self): #打开excel表 book = xlrd.open_workbook("../Data/data2.xlsx") # book = xlrd.open_workbook("../Data/data1.xlsx") #找到sheet页 table = book.sheet_by_name("Sheet1") #获取总行数总列数 row_Num = table.nrows #获取总行数总列数 col_Num = table.ncols #获取总行数总列数 s =[] key =table.row_values(0)# 这是第一行数据,作为字典的key值 if row_Num <= 1: print("没数据") else: j = 1 for i in range(row_Num-1): # print(i) d ={} values = table.row_values(j) for x in range(col_Num): # print(values) d[key[x]]=values[x] j+=1 s.append(d) return s if __name__ == '__main__': r = Read_Ex() s=r.read_excel() print(s)
unittest应用---天气测试.py
import requests import unittest import sys sys.path.append("..") from Commonlib.ReadExc import Read_Ex class Test_Tq(unittest.TestCase): def setUp(self): print("开始") def tearDown(self): print("结束") def test02(self): res1 = Read_Ex() data = res1.read_excel() for i in data: # 接口地址 url = "http://v.juhe.cn/weather/index" # 构造数据 para = {"cityname": i["cityname"], "key": i["key"]} res = requests.get(url, params=para) r = res.json() # r["reason"] # self.assertEqual(r["reason"],"查询成功!") self.assertEqual(r["error_code"], int(i["exp"])) if __name__ =='__main__': unittest.main()
案例3:订单查询
快递地址:http://www.kuaidi.com
用抓包工具
1.先不用过滤。这是承接之前的。 Filters-------Use Filters(前面的勾去掉)------Actions(点击Run Filterset now)。
2.在fiddle抓包工具中点击ie浏览器图标。在新开的ie浏览器输入:http://www.kuaidi.com/
3.清空记录两种方式
第一种:点击X中的Remove all
第二种:在下面输入cls回车
4.刷新网站,看一下打开网站后,fiddle抓包工具记录到的最后url(前面的序号)。这是重点。
打开网站,这里是16url。
5.把下面的例子,复制到输入框中去。点击查询。也可以直接点击下面的数字。
6. 从17url开始,一个个双击url,Row----JSON,查看响应数据里有没有想要的。
这里21url就有想要的签收响应数据。
比较奇怪的是:我这里post请求,老师的是get请求。
7.拷贝21ur:http://www.kuaidi.com/index-ajaxselectcourierinfo-773058962040428-shentong-XCAO1605170529820.html
这个url不是每次都一样的。所以直接拿代码运行有可能报错。
选中21url---copy----Just Url。
总的代码
(这里比较奇怪:get和post请求都可以)
# 导包 import requests import unittest class Test_Order(unittest.TestCase): def test01(self): url ="http://www.kuaidi.com/index-ajaxselectcourierinfo-773058962040428-shentong-XCAO1605159776900.html"
r = requests.post(url) res=r.json() print(res) #判断是否是韵达快递 self.assertEqual(res["company"],"申通快递") # # 判断是否签收 print(res["data"]) print(res["data"][0]) print(res["data"][0]["context"]) self.assertIn("已签收",res["data"][0]["context"]) if __name__ == '__main__': unittest.main()
知识点:
1.判断是否相等
self.assertEqual(res["company"],"申通快递")
2.判断结果是否包含
self.assertIn("已签收",res["data"][0]["context"])
运行结果:成功