python接口测试中阶篇(史无前例)
接口自动化中级篇
咱们书接上本:
接口测试基础篇(史上最详细):https://www.jianshu.com/p/eac7a9d2327f
设计思路
-
将测试用例封装成json格式,里面包含接口的各种信息
-
封装requests,能请求post get等类型的请求
-
执行用例,执行前,判断前置条件
-
判断用例是否跳过,然后在基础上增加allure测试报告
功能总结如下
-
微型框架能适应简单的各种接口请求 post get等等
-
断言只需要写一次,不需要重复的代码
-
抛开unittest和pytest等框架的约束,本次不使用这些框架!
-
执行测试用例的代码 封装成通用的,维护只需要维护json数据就可以了
-
设计思路简单而简约,先搭建简单的框架在搭建稍微复杂的
-
本次测试报告采用allure,自定义allure测试报告
-
可以适应大批量接口请求,维护简单
-
有断言,前置条件等功能
咱们的目的就是从0到1,到最后的接口自动化框架搭建,我会用自己最大的能力往框架里面带入,从简单略有难度,由浅到深的一个过程, 希望这个过程,大家能积极交流 互相学习 一起进步
allure官方文档:https://docs.qameta.io/allure
希望你能有看官方文档的习惯,因为再多的文章都不如官方文档详细,强烈建议哦!!!
请用你勤劳的双手,跟着敲一遍,不敲是学不会的哦~
第一步: 用例封装成json格式
项目下增加config.py
# 测试环境
base_url = 'http://suggest.taobao.com/'
# 假装是正式环境
# base_url = 'http://suggest.taobao.com/'
"""
title:用例的名称
condition:前置条件,写skip跳过这条用例
url:接口的链接
params:参数 如果是headers 就增加一个headers
type:请求类型 get post put 等等
isok:用例是否通过
time:这条用例是否需要等待
"""
# list里面嵌套 字典,通过循环读取获取里面的字典类型用例
httpurl_data = [
# 1.注册接口 第一条用例
{'title': '注册接口', # 用例的名称
'condition': '', # 前置条件 写skip 跳过这个用例
'url': '{}sug'.format(base_url),
'params': {
'code': 'utf-8', # 接口需要传入编码格式
'q': '裤子', # 搜索条件 如 裤子等信息
'callback': 'cb 用例'
},
'type': 'get', # 请求的类型 get 就写get post就写post
'isok': '', # 用例是否通过,通过是ok 不通过是 failure
'time': '1' # 用例等待的时间 秒 1就是等待1秒后执行
},
# 2.登录接口 第二条用例
{'title': '登录接口', # 用例的名称
'condition': '', # 前置条件 写skip 跳过这个用例
'url': '{}sug'.format(base_url),
'params': {
'code': 'utf-8', # 接口需要传入编码格式
'q': '裤子', # 搜索条件 如 裤子等信息
'callback': 'cb 用例'
},
'type': 'get', # 请求的类型 get 就写get post就写post
'isok': '', # 用例是否通过,通过是ok 不通过是 failure
'time': '' # 用例等待的时间 秒 1就是等待1秒后执行
}
]
总结: 这样写的好处就是,直接可以通过循环来执行每一条用例,并在执行过程中记录用例
第二步: 封装requests 先封装post和get类型的请求
项目下增加poshttp.py
import requests
import time
# 简单封装get请求 data={'title': '注册接口', 'condition': '', 'url': 'http://suggest.taobao.com/sug', 'params': {'code': 'utf-8', 'q': '裤子', 'callback': 'cb 用例'}, 'type': 'get', 'isok': '', 'time': '1'}
def get(data={}):
# 发送请求
r = requests.get(data['url'], data['params'])
# 简单的判断接口的code码 等于200就让它通过
if r.status_code == 200:
# 改变字典里面的值
data['isok'] = 'ok'
# 打印请求的结果
print(r.text)
# 返回字典用于记录测试报告
return data
def post(data={}):
# 发送post请求
r = requests.post(data['url'], data['params'])
# 简单的判断接口的code码 等于200就让它通过
if r.status_code == 200:
# 改变字典里面的值
data['isok'] = 'ok'
# 打印请求的返回结果
print(r.text)
# 返回字典用于记录测试报告
return data
总结:简单的封装了requests 请求完成后打印结果信息
第三步:执行用例,执行前,判断用例是否等待
项目下增加start.py
# 引入config里面的用例
from config import httpurl_data
# 引入请求
import poshttp
# time在这里的作用主要是等待的操作
import time
# 开始执行测试,并记录结果数据
result = []
# 开始执行用例
for data in httpurl_data:
# 获取等待时间 没有的话就是0
sltime = data.get('time', 0)
# 判断时间有值在进行等待
if sltime:
# 使用sleep进行等待
time.sleep(float(sltime))
# 使用getattr函数进行反射调用接口 参数1:请求的对象,参数2:请求类型 get post 后面的小括号是进行传参
case = getattr(poshttp, data['type'])(data)
# 测试结果数据添加到list中
result.append(case)
print('打印结果数据')
for r in result:
print(r)
总结:这样写 可以执行大批量的接口请求,不用每一个用例就写一个test函数等信息,遵守一些规则,这里可以根据自己的想法去做一些事情
运行start.py 来看看结果:
image
前三步咱们已经简单的做完了,接下来进行第四步
第四步:判断用例是否需要跳过,然后在基础上增加allure测试报告
allure如何安装的这里不再叙述,网上有很多教程,咱们直接开始
junit 主要用于生产自定义的allure测试报告,这里需要引入from xml.dom.minidom import Document 主要用于生成xml数据源,提供给allure展示测试报告
增加junit.py
import timeit
from xml.dom.minidom import Document
from pathlib import Path
import time
from datetime import datetime
class Junit:
def __init__(self, pstarttime):
# 创建DOM文档对象
self.doc = Document()
self.pstarttime = pstarttime
# 创建用例套件集
self.testsuites = self.doc.createElement('testsuites')
self.doc.appendChild(self.testsuites)
# 当前时间
self.nowtime = time.strftime("%Y%m%d_%H%M%S", time.localtime())
# 创建用例套件
self.testsuite = self.doc.createElement('testsuite')
# 测试用例套件
def suite(self, tests):
# 项目的名称
self.testsuite.setAttribute('hostname', 'exhibit')
# 用例数量
self.testsuite.setAttribute('tests', str(tests))
# 项目类型
self.testsuite.setAttribute('name', 'API')
# 时间
self.testsuite.setAttribute('timestamp', str(datetime.isoformat(self.pstarttime)))
# 每条用例是一个case
def case(self, title, time):
# 创建case标签
self.testcase = self.doc.createElement('testcase')
# 用例的名称
self.testcase.setAttribute('name', str(title))
self.case_timer = time
# 跳过用例的case
def skip_case(self, message):
skip = self.doc.createElement('skipped')
skip.setAttribute('message', message)
self.testcase.appendChild(skip)
# 设置时间
def settime(self):
endtime = datetime.now()
# 单个用例的执行时间
td = endtime - self.case_timer
time = float(
(td.microseconds + (td.seconds + td.days * 24 * 3600) * 10 ** 6)) / 10 ** 6
self.testcase.setAttribute('time', str(time))
self.testcase.setAttribute('priority', 'M')
self.testsuite.appendChild(self.testcase)
# 失败的用例
def failure(self, message):
# 创建失败用例的标签
failure = self.doc.createElement('failure')
# 为什么失败了这个用例
failure.setAttribute('message', str(message))
# 类型为失败
failure.setAttribute('type', 'Failure')
# 添加到testcase下
self.testcase.appendChild(failure)
# 生成xml 是allure的数据源
def write_toxml(self):
# 计算执行的时间, 用当前时间-开始时间 是总耗时
td = datetime.now() - self.pstarttime
td_time = float(
(td.microseconds + (td.seconds + td.days * 24 * 3600) * 10 ** 6)) / 10 ** 6
self.testsuite.setAttribute('time', '%s' % td_time)
self.testsuites.appendChild(self.testsuite)
file = Path('junit') / ('API' + '-' + 'ReportJunit@' + self.nowtime + '.xml')
f = open(file, 'w')
self.doc.writexml(f, indent='\t', newl='\n', addindent='\t', encoding='gbk')
f.close()
接下来修改start.py 增加了跳过用例,和生成xml测试报告的代码,代码不是很多,注释很详细,贴代码大家来看看吧~
# 引入config里面的用例
from config import httpurl_data
# 引入请求
import poshttp
# time在这里的作用主要是等待的操作
import time
from datetime import datetime
# 引入junt
from junit import Junit
from pathlib import Path
files = ('junit',)
# 创建文件夹
for k in files:
path = Path(k)
# 如果文件不存在 则创建
if not path.is_dir():
path.mkdir()
# 获取程序执行的时间
start_time = time.strftime("%Y%m%d_%H%M%S", time.localtime())
# 获得junit实例
junit = Junit(datetime.now())
# 开始执行测试,并记录结果数据
result = []
# 开始执行用例
for data in httpurl_data:
# 判断需要跳过的用例
if data['condition'] == 'skip':
# 写入跳过用例标题名
junit.case(data['title'], datetime.now())
# 跳过用例的信息
junit.skip_case('This use case is skipped')
junit.settime()
# 跳过的用例也添加到结果里面
result.append(data)
# continue 跳出本次循环不会结束循环
continue
# 这条用例开始执行的时间
case_time = datetime.now()
# 首先判断此用例是否需要执行
# 获取等待时间 没有的话就是0
sltime = data.get('time', 0)
# 判断时间有值在进行等待
if sltime:
# 使用sleep进行等待
time.sleep(float(sltime))
# 使用getattr函数进行反射调用接口 参数1:请求的对象,参数2:请求类型 get post 后面的小括号是进行传参
case = getattr(poshttp, data['type'])(data)
# 看结果里 接口是否为通过
is_pass = case.get('isok', '')
# 用例通过
if is_pass == 'ok':
# 写入xml测试报告
junit.case(case['title'], case_time)
junit.settime()
# 用例不通过
else:
junit.case(case['title'], case_time)
junit.failure('标题:' + case['title'] + '请求类型' + case['type'])
junit.settime()
# 测试结果数据添加到list中
result.append(case)
# 生成xml数据源 提供给allure
# 生成测试套件 参数为用例的总数
junit.suite(len(httpurl_data))
junit.settime()
# 生成xml
junit.write_toxml()
执行完毕,在项目里面生产了junit文件夹,里面有xml测试报告 那么如何如何生成allure测试报告呢?,如果你配置好了,在当前项目的路径下执行:allure serve junit 就会生成allure测试报告了,在你已经配置好allure的情况下
进行如下操作:
输入:allure serve junit
image
会自动打开浏览器,展示allure测试报告 截图如下:
image
image
image
allure 已经增加完了,接下来增加接口的断言功能
在config.py下面增加assert字段
然后修改下poshttp.py就可以了,在里面增加一个断言的代码
poshttp.py修改完之后的如下
import requests
import time
# 简单封装get请求 data={'title': '注册接口', 'condition': '', 'url': 'http://suggest.taobao.com/sug', 'params': {'code': 'utf-8', 'q': '裤子', 'callback': 'cb 用例'}, 'type': 'get', 'isok': '', 'time': '1'}
def get(data={}):
# 发送请求
r = requests.get(data['url'], data['params'])
# 简单的判断接口的code码 等于200就让它通过
if r.status_code == 200:
# 改变字典里面的值
data['isok'] = 'ok'
# 取出来需要断言 数据 取出来是个元祖类型,需要挨个去返回结果里面对比
content = data.get('assert', '')
for ct in content:
# 每个字段和去街口的返回值去对比
if ct in str(r.text):
pass
else:
data['isok'] = 'failure'
print(ct + '这个没有通过')
# 打印请求的结果
print(r.text)
# 返回字典用于记录测试报告
return data
def post(data={}):
# 发送post请求
r = requests.post(data['url'], data['params'])
# 打印请求的结果
print(r.text)
# 简单的判断接口的code码 等于200就让它通过
if r.status_code == 200:
# 改变字典里面的值
data['isok'] = 'ok'
# 取出来需要断言 数据 取出来是个元祖类型,需要挨个去返回结果里面对比
content = data.get('assert', '')
for ct in content:
# 每个字段和去街口的返回值去对比
if ct in str(r.text):
pass
else:
data['isok'] = 'failure'
print(ct + '这个没有通过')
# 打印请求的返回结果
print(r.text)
# 返回字典用于记录测试报告
return data
image总结:主要增加了 这几行代码 ,将返回的信息强转为str类型,然后用in 来判断返回的接口里面,有没有咱们想要的内容
content = data.get('assert', '')
for ct in content:
# 每个字段和去街口的返回值去对比
if ct in str(r.text):
pass
else:
data['isok'] = 'failure'
print(ct + '这个没有通过')
到这里一个微小型框架就已经差不多成型啦,能支持简单的请求了,有问题欢迎交流沟通
qq群:234922431 欢迎来交流互相学习