接口测试的原理就是模拟客户端向服务器发送请求,服务器接收请求报文后对相应的报文做处理并向客户端返回应答,客户端接收应答的过程。
接口测试采用的方法其实与黑盒测试一致的,甚至可以把接口测试理解为没有界面的功能测试。只不过接口测试的关注点主要在请求和响应上。另外,还包括接口的安全,接口的性能等。常用的用例设计有等价类,边界值法等。
一般测试用例的设计要从单接口参数的校验到整个业务功能点的验证,还可以验证一些安全性和异常情况。
状态码 | 含义 |
---|---|
1** | 临时响应并需要请求者继续执行操作 |
2** | 请求成功。操作被成功接收并处理 |
3** | 重定向代码,用于已经移动的文件并且在头信息中指定新的地址信息 |
4** | 客户端错误,请求包含语法错误或者无法完成请求 |
5** | 服务器错误,服务器在处理请求的过程中发生错误 |
比如:
200 服务器成功处理请求
404 未找到资源
410 找到资源,但现在已不存在
500 内部服务器错误
503 服务器目前无法为请求提高服务
302 临时重定向
304 客户端的缓存资源时最新的,要客户端使用缓存
DNS:Domain Name Server 域名服务器
http:// www.baidu.com: 80/ adv_search? w=py&order=false# tag
HTTP报文格式分为两种
请求报文:请求行,请求头部,回车换行,消息体
响应报文:状态行,响应头部,回车换行,消息体
HTTP由请求和响应构成,是一个标准的客户端服务器模型(B/S架构)。HTTP协议永远都是客户端发起请求,服务器回送响应。B/S架构又叫浏览器/服务器模型,严格意义上说,这个B不仅仅只是浏览器,凡是能够发生HTTP请求的对象或者工具,都可以叫做客户端。
URL地址,请求参数(可选),请求头,请求体(仅限POST请求)
对于响应内容部分,主要关注两个点:响应状态码,响应内容
HTTP工作过程
Get和Post
Get:从服务器端获取资源或数据
Post:向服务器端提交数据
Get和Post的区别:
1)Get请求一般用于向服务器请求获取一个资源,没有副作用,一般会在客户端做缓存。Post请求一般用于向服务器提交数据并让其去完成一件事,所以这个操作是有副作用的,不会在客户端做缓存,
2)Get请求发送数据的时候,一般会将请求数据放在url字符串中发送给服务器端,所以从安全性角度来看相对没有Post请求安全性搞,所以get请求一般不会用于比较隐私数据的传输。而Post请求时将请求数据放在请求体body里面,所以一般用于表单数据,登录数据等数据的传输。
cookie
存在于客户端,由服务器端通过set.cookie方法来进行设置。
session
存在于服务器端的内存中,主要用于和cookie一起来验证客户端的登录状态。
token
token是服务器端生成的一串字符串,用作于客户端进行请求的一个令牌。
token运行的原理:
(1)客户端第一次登录成功时,由服务器端生成,并保存于服务器端的数据库中,服务器端再将token值返回给客户端。
(2)客户端拿到token值之后,会进行保存(保存位置由服务器端指定)。
(3)后面客户端发送请求时,会将token值附带在请求参数中发送给服务器进行验证。
(4)服务器端收到客户端的请求之后,会取出token值与保存在本地数据库中的token值进行比较。
(5)如果两个token是一致的,说明用户已登录成功,当前用户处于登录状态。
(6)如果没有这个token值,说明用户没有登录过。
(7)如果token值已经发生改变,说明原登录信息已经失效,需要重新登录。
Fiddler是通过改写HTTP代理,让数据从它那通过,来监控并且截取到数据。在打开它的那一瞬间,它就已经设置好了浏览器的代理了。当你关闭的时候,它又帮你把代理还原了。
官网下载:https://www.telerik.com/fiddler
按照指示填写,下载,然后傻瓜式安装,一直点击是就可以安装成功。
名称 | 含义 |
---|---|
# | 抓取HTTP Request的顺序,图标表示请求状态和响应状态 |
Result | HTTP状态码 (重点关注) |
Protocol | 请求使用的协议,常用HTTP,HTTPS |
Host | 请求地址的主机名 |
URL | 请求资源的位置 |
Body | 请求的大小 |
Caching | 请求的缓存过期时间或者缓存控制值 |
Content-Type | 请求响应的类型 |
Process | 发送此请求的进程:进程ID |
Comments | 允许用户为此回话添加备注 |
Custom | 允许用户设置自定义值 |
要访问HTTPS协议需要设置一下:Tools –> Fiddler Options ,选择HTTPS,勾选Decrypt HTTPS TrafficDecrypt,然后后面弹出的窗口都点击yes/是,点击Actions,最后点击OK
名称 | 含义 |
---|---|
Statistics | 请求的性能数据分析 |
Inspectors | 查看数据内容(常用) |
AutoResponder | 允许拦截指定规则的请求 |
Composer | 自定义请求发送服务器 |
Filters | 请求过滤规则(常用) |
Timeline | 请求响应时间 |
过滤最常用,过滤掉不需要的抓包数据,只显示自己需要的,这样看起来会方便很多。
Before Request断言
Before Response断言
安装Requests库:pip install requests
import requests
def test1():
resp = requests.get('http://www.taobao.com')
print(resp.status_code) # 响应的状态码信息
print(resp.text) # 获取响应对象的文本信息
print(resp.url) # 获取响应对象所对应的请求地址
if __name__ == '__main__':
test1()
import requests
# 直接在url上添加请求参数
def test1():
resp = requests.get('https://baidu.com/s?wd=python') # 自动在url后面添加参数
print(resp.text)
# get请求+参数
def test2():
data = {
'wd': 'python'
} # 请求参数
resp = requests.get('https://baidu.com/s', params=data) # 自动在url后面添加参数
print(resp.text)
if __name__ == '__main__':
test2()
import requests
def test1():
resp = requests.post('https://ynuf.aliapp.org/service/um.json?_bx-v=2.0.31')
print(resp.status_code) # 响应的状态码信息
print(resp.text) # 获取响应对象的文本信息
print(resp.url) # 获取响应对象所对应的请求地址
if __name__ == '__main__':
test1()
import requests
# 以json格式传
def test1():
data = {"username": "test", "password": "123", "age": 18, "phone": 1588888888} # 字典格式是json
resp = requests.post('', json=data)
print(resp.text)
if __name__ == '__main__':
test1()
如果浏览器访问,响应正常,如果不是浏览器来访问,是爬虫或代码访问,则响应不正常。这个需要用到headers信息。
import requests
# 含有header访问才能跟浏览器访问显示一样的
def test1():
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36'
}
resp = requests.get('', headers=headers)
print(resp.text)
if __name__ == '__main__':
test1()
import requests
# 绕过登录,想要获取登录之后的信息,需要带上Cookie
def test1():
headers = {
'Cookie': '' # 每次都要更新
}
resp = requests.get('', headers=headers)
print(resp.text)
if __name__ == '__main__':
test1()
需要登录才能访问的接口,对于这种一定要使用session会话来帮助保存会话信息
import requests
# 利用session保持会话状态
def test1():
sess = requests.Session() # 创建一个session会话对象,帮助我们保存客户端的会话信息
data = {
'username': 'admin',
'password': 'admin123'
}
sess.post('', data=data) # 操作登录
resp2 = sess.get('') # 请求登录之后的接口
print(resp2.text)
if __name__ == '__main__':
test1()
import requests
# 上传文件不带参数
def test1():
files = {
'file': open('test.txt', 'rb')
}
resp = requests.post('', files=files)
print(resp.text)
# 上传文件带其他参数
def test2():
data = {
'batchname': 'GB20210707' # 抓包的
}
files = {
'batchfile': open('Test.xls', 'rb')
}
resp = requests.post('', data=data, files=files)
print(resp.text)
if __name__ == '__main__':
test1()
询问开发用的什么加密方法
import requests
# 加密接口请求
def test1():
uid, name, password, salt = '3', 'qcj', '123456', 'LZ7dYxCj5S68ucAh'
import hashlib # 有MD5加密方法
hl = hashlib.md5()
hl.update(('{}-{}-{}-{}'.format(uid, name, password, salt)).encode('utf-8'))
sign = hl.hexdigest() # 对hl对象中保存的字段进行md5加密算法
print(sign)
data = {
'uid': '3',
'sign': sign
}
resp = requests.post('', json=data)
print(resp.text)
if __name__ == '__main__':
test1()
import requests
# 接口参数关联(下一个请求的入参是上一请求的出参)
def test1():
data = {
'username': 'qcj',
'password': '123456'
}
resp = requests.post('', data=data) # 请求第一个接口
resp_json = resp.json() # 第一个接口响应的json内容
auth_token = resp_json['data'] # 提取第一个接口的data出参
headers = {
'auth-token': auth_token
}
resp = requests.get('', headers=headers) # 请求第二个接口
print(resp.text)
if __name__ == '__main__':
test1()
为什么我们需要关心接口返回的响应值
原因:我们需要对返回的响应内容进行断言,对比实际结果与预期结果,从而验证接口工作是否正常。
接口响应内容的形式?
主要有三种形式:JSON格式的字符串;HTML源码;程序员自定义的字符串。
主要的处理方式?
处理方式1:正则表达式来进行处理,这种方法适合以上三种响应内容形式。
处理方式2:lxml库进行处理,这种方式仅针对返回内容是HTML源码形式的。
处理方式3:直接使用requests库自带的json方法进行处理,这种方式仅针对返回内容是json形式的。
获取指定内容最常用的一个正则表达式.*?的使用。
import re # 正则表达式的库
log = '''
now: 2020-04-15 23:44:34 id: ST0013 status: nok
now: 2020-04-26 09:33:14 id: DAMX002 status: good
now: 2020-04-17 22:27:39 id: SIMKOIF0 status: well
now: 2020-04-18 16:45:30 id: 04 status: unknown
'''
# \s表示空格 \d{4}表示4个十进制数字开始 \s+表示一个或多个空格
dt = re.findall('now:\s(\d{4}-\d{2}-\d{2})\s+(\d{2}:\d{2}:\d{2})', log)
# \s+表示一个或多个空格 \w*表示任意个字母 \d+表示一个或多个十进制数
sid = re.findall('id:\s+(\w*\d+)', log)
# \s+表示一个或多个空格 \w+表示一个或多个字母
status = re.findall('status:\s+(\w+)', log)
print(dt)
print(sid)
print(status)
import re # 正则表达式的库
# 从文件中截取某个字段的值
with open('zzlb.txt', 'r') as f:
content = f.read()
result = re.findall('"SNAME":"(.*?)"', content) # 截取文件中SNAME字段的值
print(result)
import re # 正则表达式的库
# 正则表达式中换行符的处理
content = '''
'''
result = re.findall("href='(.*?)'", content, re.S) # 处理html格式的,有换行符的需要加re.S
print([item.strip() for item in result]) # \n相当于空格,可以用strip去掉
lxml库进行处理,这种方式仅针对返回内容是HTML源码形式的。
例子:登录进去的页面,会有注销或者退出登录的字段,验证登录是否成功,可以提取登录进去页面的HTML源码中的注销字段来验证。
# 解析HTML文档格式响应
from lxml import etree
import requests
def verifylogin():
headers = {
'cookie': '' # 登录后的cookie
}
resp = requests.get('', headers=headers) # 登录后的url
resp.encoding = 'utf-8' # 防止中文乱码
html = etree.HTML(resp.text) # 获取登录后页面的HTML
result = html.xpath("//a[@href='javascript:logoff()']/text()") # 获取指定a元素上显示的文本信息
print(result)
if __name__ == '__main__':
verifylogin()
查看json格式的网站:bejson
要先清楚响应内容的json结构,层级,字典里面的层级。
响应内容:
import requests
def verifylogin():
headers = {
'cookie': '' # 登录后的cookie
}
data = {
'page': '1',
'rows': '5'
} # 参数
resp = requests.post('', headers=headers, data=data) # 登录后的url
resp_json = resp.json() # 通过json方法将resp对象转换为一个json对象
print(resp_json['people'][1]['lastName'])
if __name__ == '__main__':
verifylogin()
Apifox是接口管理,开发,测试全流程集成工具,通过一套系统,一份数据,解决多个系统之间的数据同步问题。只要定义好接口文档,接口调试,数据Mock,接口测试就可以直接使用,无需再次定义。接口文档和接口开发调试使用同一个工具,接口调试完成后即可保证和接口文档定义完全一致。高校,及时,准确。
Postman + Swagger + Mock + JMeter = ApiFox
接口关联(上一个请求的响应内容有作为下个请求的入参)
第一个请求后置操作添加变量
第二请求,可将变量值作为headers值,或参数值
命令的方式运行接口自动化脚本
(1)先安装apifox-cli库,cmd中输入命令
nmp install -g apifox-cli
如果报错unable to verify the first cortificato,则分别输入以下两个命令
npm config set strict-ssl false
nmp install -g apifox-cli
(2)然后将apifox中的测试用例导出来
(3)将到处的自动化脚本和测试数据文件放在一一个目录,在这个目录下打开cmd,输入命令
apifox run 测试用例文件名 -d 测试数据文件名 -n 2 -r html
-d 测试用到的数据文件,比如data.csv
-n 循环次数
-r 在当前路径生成测试报告,并指定报告格式
例如:apifox run 回归测试 -d 测试数据文件名 -n 2 -r html
例如:apifox run 回归测试.apifox-cli.json -d data.csv -n 2 -r html