一、接口自动化介绍
1.简介
[接口自动化]是提高测试效率和质量的重要手段之一。
2.为什么要做接口自动化
相对于UI自动化而言,接口自动化具有更大的价值。
为了优化转化路径或者提升用户体验,APP/web界面的按钮控件和布局几乎每个版本都会发生一次变化,导致自动化的代码频繁变更,没有起到减少工作量的效果。
而接口一旦研发完成,后期重构/大幅度修改的频率则比较低.因而做接口自动化性价比还是很高的,对于迭代版本旧有功能的回归,beta测试,线上回归都能起到事半功倍的作用。
3.接口自动化两大类
1、为模拟测试数据而开展的接口自动化
这种接口自动化大多是单次执行,目的很明确是为了功能测试创造测试数据,节约人工造数据的时间和人工成本,提高功能测试人员的测试效率。
2、在功能测试之前提前发现错误而开展的接口自动化
这种接口自动化的工作流程跟功能测试一样,需要设计接口测试用例,然后执行接口测试用例。
说白了就是对单接口进行功能校验,包括接口参数的必填性、长度字符类型限制、入参枚举值等是否正确、响应数据是否正确等进行校验。
4.插件自动安装
1、在项目根目录创建文件:requirements.txt
2、在文件中写入需要安装的插件名
requirements.txt 内容
pytest
requests
pytest-html
pytest-xdist
pytest-ordering
pytest-rerunfailures
pytest-base-url
allure-pytest
二、Requests简介
1.Requests是基于urllib,使用Apache2 许可证开发HTTP库。其在python内置模块的基础上进行了高度封装,使得Requests能够轻松完成浏览器相关的任何操作。
2.接口测试流程
发起请求: 通过HTTP库向目标站点发起请求,等待目标站点服务器响应。
获取响应: 若服务器正常响应,会返回一个Response,该Response
即为获取得页面内容,Response可以是HTML、JSON、字符串、
二进制数据等数据类型。
解析内容:利用正则表达式、网页解析库对HTML进行解析;
将json数据转为JSON对象进行解析;保存我们需要得二进制数据
(图片、视频)。
内容断言:根据解析内容断言期望结果。
3.Requests总览
使用requests发送get请求
以访问百度为例,访问百度时,是使用的get请求,所以这里调
用requests.get()方法,将返回结果用resp接收,这里因为
响应结果是乱码,所以这里把返回结果编码设置为utf-8
import requests
def fun1():
resp = requests.get("http://www.baidu.com") #request发送不带参数的get请求
resp.encoding="utf-8" #防止中文乱码,设置响应内容编码格式
print(resp.status_code) #输出响应状态码
print(resp.text) #获取响应的文本信息
if __name__ == "__main__":
fun1()
#发送get请求带参数--请求格式为字典,使用params参数
以访问百度为例,这里是在百度搜索python,后面增加了一个参数
wd,也可以直接用
resp = requests.get(["](http://www.baidu.com/s """)http://www.baidu.com/s?wd=python"),下面把url和请求参数分别用变量接收
def fun2():
data_dict={"wd":"python"}
req_url="http://www.baidu.com/s"
resp = requests.get(url=req_url,params=data_dict)
print(resp.status_code)
使用requests发送post请求
post请求的参数分为两种情况,请求头中Content-type是
application/x-www.form-url,后面的参数就是data,
请求头中Content-type是application/json,参数就用json
response = request.post(url,data=None,json=None)
data:参数接收form表单数据,后台会自动附加form表单请求信息头
header={"Content-Type":"application"}
json:参数接收json数据时,后台会自动附加json表单请求信息头
header={“Content-Type”:“application/json”}
data参数提交数据
import requests
url = 'http://httpbin.org/post'
"""带data数据的post"""
data = {'key1':'value1','key2':'value2'}
response = requests.post(url,data=data)
print(response.status_code)
print(response.text)
"""带json数据的post"""
import requests
url_login = "http://ihrm-java.itheima.net/api/sys/login"
#无论表单data还是json,都是用字典发送请求
login_json = {
"mobile" :"17743533546",
"password" : "123456"
}
response = requests.post(url=url_login,json=login_json)
#查看响应
print(response.json())
响应公共方法
请求方法的返回值response为Response对象,我们可以从
这个对象中获取所有我们想要的响应信息。
response.status_code 状态码
response.url 请求url
response.encoding 查看响应头部字符编码
response.headers 头信息
response.cookies cookie信息
response.text 文本形式的响应内容
response.content 字节形式的响应内容
response.json() JSON形式的响应内容
import requests
# 1). 访问百度首页的接口`http://www.baidu.com`,获取以下响应数据
response = requests.get("http://www.baidu.com")
# 2). 获取响应状态码
print("响应状态码",response.status_code)
# 3). 获取请求URL
print("请求url",response.url)
# 4). 获取响应字符编码
print("响应字符编码",response.encoding)
# 5). 获取响应头数据
print("响应头数据",response.headers)
#提取响应头数据中某个键的值
print("Content-Type",response.headers.get("Content-Type"))
# 6). 获取响应的cookie数据
print("cookie数据",response.cookies)
print("提取指定的cookie",response.cookies.get("BDORZ"))
# 7). 获取文本形式的响应内容
print("文本形式内容",response.text)
# 8). 获取字节形式的响应内容
print("响应内容",response.content)
其他
如果需要为请求添加请求头数据,只需要传递一个字典类型的
数据给 headers 参数就可以了
"""
1. 请求IHRM项目的登录接口,URL: http://ihrm-java.itheima.net/api/sys/login
2. 请求头: Content-Type: application/json
3. 请求体: {"mobile":"17743533546", "password":"123456"}
"""
#设置请求头
import requests
url_login = "http://ihrm-java.itheima.net/api/sys/login"
#请求头是一个键值对
header = {
"Content-Type":"application/json"
}
login_data = {
"mobile":"17743533546",
"password":"123456"
}
response = requests.post(url=url_login,json=login_data,headers=header)
response.encoding = 'utf-8'
print(response.json())
"""下载图片"""
import requests
import matplotlib.pyplot as plt
url = 'https://cn.bing.com/images/search?view=detailV2&ccid=qr8JYj0b&id=6CEE679B0BCE19C94FB9C7595986720942C92261&thid=OIP.qr8JYj0bcms3xayruiZmnAHaJQ&mediaurl=https%3a%2f%2ftse1-mm.cn.bing.net%2fth%2fid%2fR-C.aabf09623d1b726b37c5acabba26669c%3frik%3dYSLJQglyhllZxw%26riu%3dhttp%253a%252f%252fp1.ifengimg.com%252f2019_02%252f95A41E54C3C8EB3B3B148A30CE716314B0AED504_w1024_h1280.jpg%26ehk%3d2EhKcVkSnCvT6uBfgisn%252fdwtghMXFWjGa5WgqEbBSPc%253d%26risl%3d%26pid%3dImgRaw&exph=1280&expw=1024&q=%e7%9f%b3%e5%8e%9f%e9%87%8c%e7%be%8e&simid=607996751665040666&FORM=IRPRST&ck=399D74E04F8507D6711ADC8F53A714D7&selectedIndex=0&ajaxhist=0&ajaxserp=0'
response = requests.get(url)
img = response.content
with open('shiyuanlimei.jpg','wb') as f:
f.write(img)
"""接口参数关联请求"""
datas = {
"username":"qcj",
"password":"123456"
}
login_url = "http://www.fanyunedu.com:5000/general/login_token"
rep = requests.post(url=login_url,data = datas)
req_json = rep.json()
token =req_json['data']
headers = {
"auth-token":token
}
t_url="http://www.fanyunedu.com:5000/general/userinfo_token"
t_req = requests.get(url=t_url,headers=headers)
"""加密接口请求"""
uid,name,password,salt='3','qcj','123456','LZ7dYxCj5S68ucAh'
import hashlib
hl = hashlib.md5()
hl.update('{}-{}-{}-{}'.format(uid,name,password,salt).encode('utf-8'))
sigh = hl.hexdigest()#对hl对象中保存的字段进行md5的加密算法
datas={"uid":"3","sign":sigh}
url_data = "http://www.fanyunedu.com:5000/general/userinfo_sign"
req = requests.post(url=url_data,json=datas)
三、Yaml知识点
1.Yaml简介
YAML 是一种可读性非常高,与程序语言数据结构非常接近。同时具备丰富的表达能力和可扩展性,并且易于使用的数据标记语言。
其实YAML文件也是一种配置文件,但是相较于ini,conf配置文件来说,更加的简洁,操作简单,还能存放不同类型的数据;而像ini存储的值就都是字符串类型,读取之后还要手动转换
2.YAML的基本语法规则
大小写敏感
使用缩进表示层级关系
缩进时不允许使用Tab键,只允许使用空格。(可以将你的ide的tab按键输出替换成4个空格)
缩进的空格数目不重要,只要相同层级的元素左侧对齐即可
表示注释
3.YAML支持的数据结构
对象:键值对的集合,又称为映射(mapping)/ 哈希(hashes) / 字典(dictionary)
数组:一组按次序排列的值,又称为序列(sequence) / 列表(list)
纯量(scalars):单个的、不可再分的值
4.YAML,对象数据类型
对象的一组键值对,使用冒号结构表示。
animal: dogs
转换成Python数据结构,如下:
{'animal': 'dogs'}
将所有键值对赋值。
hash: { name: Steve, foo: bar }
转换成Python数据结构,如下:
{'hash': {'name': 'Steve', 'foo': 'bar'}}
将列表赋值
lists : [1,2,3]
转换成Python数据结构,如下:
{'lists': [1, 2, 3]}
将元组赋值
tuples : (1,2,3)
转换成Python数据结构,如下:
{'tuples': '(1,2,3)'}
总结
当赋值列表、键值对时,转换成Python数据结构是可以直接当列表、字典使用的;
当赋值元组时,转换后也是字符串
最终输出的都是字典类型,可以通过key获取对应的值
以 - 开头的行表示构成一个数组
四、python+requests+pytest+yaml+allure接口自动化框架
四.框架的介绍:
1.common层构建基础类库:为了提高测试用例的可维护性性和复用性,其中包括日志输出,接口统一发送请求,yaml文件的读取,
写入,清除的方法
2.data层:存放测试用例yaml数据
3.logs层:存放日志
4.reports层:存放生成的allure报告
5.temps层:存放生成的临时报告
6.testcase层:测试用例
7.pytest.ini:配置文件
8.requirements.txt:依赖包
9.run.py:自动化框架运行脚本的文件,然后会在reports生成allure报告
框架的使用说明:
1.环境配置:需要在pycharm终端里安装requirements.txt依赖包,输入pip install -requirements.txt部署环境
2.编写测试用例数据是用yaml文件进行传参,其中包含测试所有API的参数,这个文件可以包括
接口名称(name),请求(request),请求方法(menthod),请求路径(URL),请求参数(params)
举例:
- name: 获取接口统一鉴权码token接口
request:
method: get
url: https://api.weixin.qq.com/cgi-bin/token
params:
grant_type: client_credential
appid: XXXXXXXXXXXX
secret: XXXXXXXXXXXXX
3.测试用例以test_XXX命名,XXX是测试用例的名字,其中包括allure标记的装饰器,数据驱动,断言,
@allure.story(),allure.dynamic.title()是allure标记的装饰器
@pytest.mark.parametrize("caseinfo", read_testcase("./data/test_get_token.yaml"))
这行代码使用了pytest框架提供的 @pytest.mark.parametrize()装饰器,具体含义是read_testcase()yaml文件
读取的函数从路径"./data/test_get_token.yaml"文件中读取到测试用例数据集作为参数,将其命名为caseinfo,并
传递给被装饰器的测试函数.
test_get_token()的测试函数,该函数使用了参数化方式运行多组测试用例,每组测试用例都是一个字典函数,包含了请求参数
和预期结果信息,用yaml数据格式进行value:key方式进行传参.
断言用是pytest自带的断言方式assert
举例:
@pytest.mark.parametrize("caseinfo", read_testcase("./data/test_get_token.yaml"))
@allure.story("获取token接口")
def test_get_token(self, caseinfo):
allure.dynamic.title("获取token")
method = caseinfo["request"]["method"]
url = caseinfo["request"]["url"]
params = caseinfo["request"]["params"]
res = RequestUntil().send_request(method=method, url=url, params=params)
print(res.json()["access_token"])
write_yaml(res.json()["access_token"])
assert res.status_code== 200
assert "access_token" in res.text
4.执行测试
点击run.py文件.执行脚本,然后会在reports包里生成一份allure报告,点击idex.html,点击浏览器就可以查看
本地allure报告