接口自动化测试框架-AIM
最近在做公司项目的自动化接口测试,在现有几个小框架的基础上,反复研究和实践,搭建了新的测试框架。利用业余时间,把框架总结了下来。
AIM框架介绍
AIM,是Automatic Interface Monitoring的简称,即自动化接口监测。是一种基于python unittest的自动化接口测试框架。
设计思想
框架根据python语言的特点,结合了面向对象和面向函数编程。
以高效编程为主要目的,避免为了封装而封装。轻配置,重编码。
接口测试的主要处理对象是参数。如果完全进行数据与代码的分离,就会造成变量,传参的冗余,降低编程效率。
于是从不做数据与代码分离出发,对于需要复用的参数,提取到类之外,视需要进行数据与代码的分离。
做到有的放矢。兼顾效率和复用性,迭代分离,更具实用性。
目录结构
case:测试用例
common:公共函数,全局变量
config:配置路径
data:数据文件
result:测试结果
util:工具类
run.py:用例执行入口
case
BaseCase
所有Case的基类。调用assertEqual等方法,封装了用例的断言。比如检查接口返回flag,检查接口状态200,检查值相等。
项目Case
测试系统的用例。按模块分别建立文件编写脚本。
Env.py:环境配置,包括url处理,登录对象login实例(用户名、密码),数据库对象dao实例(数据库连接)。
Public.py:公共模块。存放本系统公共的变量、函数、用例等。
common
Func.py:公共函数,比如获取时间日期,获取随机数。
Login.py:登录模块,属于各系统通用,故放于此目录下。包括密码加密,验证码处理,强制登录。
Parewise.py:结对测试。一种测试技术,后文详述。
Var.py:全局变量。比如token。
config
RelativePath.py:配置目录、文件的相对路径。
data
echarts数据存储csv文件,项目接口清单等。
result
log:日志。logging实现。支持输出到文件和打印控制台。文件暂时使用较少,主要打印控制台便于调试。
接口调用记录:输出每个测试方法调用接口的记录,包括参数、响应、耗时等。
自动化测试报告:HTMLTestRunner.py实现的html页面报告。
util
AutoCode.py:自动生成结构化测试代码。
CSV.py:csv相关函数封装。比如输出接口调用记录。
Excel.py:读取和存储excel文件。
Format.py:格式化。比如把浏览器复制的参数格式化为代码中带有缩进的json。
HTMLTestRunner.py:用于输出自动化测试报告。
Log.py:封装日志方法。
Mysql.py:数据库相关操作。
Request.py:核心工具,封装接口发送请求。
Mail.py:发送邮件。
run.py
执行测试用例入口,可以选择执行一个或多个系统,也可以执行一个系统中一个或多个模块。
核心模块
Request
通过requests封装的发送接口请求的方法。
参数 | 说明 |
---|---|
p | 将url、headers、body、method统一封装到一个json里面进行处理。 |
method='post' | 默认为post方法。接口以post居多。 |
jsondata='json' | 默认json参数。post方法的json或data,纯json使用json参数即可。对于receive_json这种dict,采用data参数。 |
loglevel=3 | 默认为3。日志级别,输出请求、响应信息到控制台或接口调用记录.csv。 |
rtext=None | 一些get请求会返回html或pdf,在控制台或csv文件中影响显示,可以指定文本进行替换。 |
自动设置token:
if "headers" not in p.keys(): p['headers'] = {'token': ''} p['headers']['token'] = Var.token
发送请求,并计算耗时:
start = time.clock() if method == 'post': # 关闭SSL认证 if jsondata == 'json': r = requests.post(p['url'], headers=p['headers'], json=p['body'], verify=False) elif jsondata == 'data': r = requests.post(p['url'], headers=p['headers'], data=p['body'], verify=False) else: print('data_type错误') elif method == 'get': r = requests.get(p['url'], headers=p['headers'], params=p['body']) else: print('method错误') end = time.clock() elapsed = decimal.Decimal("%.2f" % float(end - start))
Parewise
结对测试。接口参数一般是多个,于是比较适合采用parewise进行用例设计。
parewaise的概念可以百度一下。
大概意思就是,大多数的bug都是条件的两两组合造成的,parewise就是针对两两组合的情况,设计测试用例。
算法为,如果某一组用例的组合结果,在其他组合中均出现,就删除该组用例,从而精简用例。
windows下有微软的PICT,txt文件录入参数后,命令行执行,就出来结果了。
比如参数
执行后结果,只有31条,精简了很多。
这个基本上一秒就出来结果了。
我自己参考网上算法写的,就要慢的多。
估计后面有时间了再看看能不能调优。
parewise算法:
cp = [] # 笛卡尔积 s = [] # 两两拆分 for x in eval('itertools.product' + str(tuple(param_list))): cp.append(x) s.append([i for i in itertools.combinations(x, 2)]) del_row = [] s2 = copy.deepcopy(s) for i in range(len(s)): # 对每个进行匹配 t = 0 for j in range(len(s[i])): # 判断所有同时都存在其他中 且位置相同 for i2 in [x for x in range(len(s2)) if s2[x] != s[i]]: # 其他 只比对有效 flag = False for j2 in range(len(s2[i2])): if s[i][j] == s2[i2][j2] and j == j2: t = t + 1 flag = True break if flag: break if t == len(s[i]): del_row.append(i) s2.remove(s[i]) return [cp[i] for i in range(len(cp)) if i not in del_row]
网上的例子是用的index函数。在我写过程中,发现这里有个坑。比如list中存在相同元素,就始终返回前一个匹配的索引,结果就会有问题。我就完全避免了index函数。不知道哪个是对的,目前满足使用需要,将就着用了。有点小尴尬。
Case
BaseCase断言:
def check_flag(self, flag, response, msg=True): """预期,实际""" msg = response.text if msg else None if isinstance(flag, list): b = False for f in flag: if f == response.json()['flag']: b = True break self.assertEqual(True, b, msg=msg) else: try: self.assertEqual(flag, response.json()['flag'], msg=msg) except json.JSONDecodeError: # 返回的不是json,比如下载、404 self.check_200(response, msg) except KeyError: self.check_200(response, msg) def check_200(self, response, msg=True): self.assertEqual(200, response.status_code, msg=msg)
最简单的一个测试用例:
class Home(BaseCase): """首页""" @classmethod def setUpClass(cls): Var.token = login.get_token() def setUp(self): log(testname(self.__repr__()) + '\n') record([testname(self.__repr__())]) def test_bankingSectorDisplay(self): """xxx""" p = { "url": full_url("xxx"), "body": {} } self.check_flag(1, request(p))
setUpClass,设置登录token。
setup,输出日志。
CSV
写文件:
if not os.path.exists(path): f = open(path, 'a', newline='') a = csv.writer(f) a.writerow(title) f.close() f = open(path, 'a', newline='') a = csv.writer(f) try: a.writerow(d) except UnicodeEncodeError: d[4] = "Unicode隐藏" # response a.writerow(d) f.close() if get_file_size(path) >= 50 * 1024 * 1024: # 超过50M删除文件 os.remove(path) record(title)
traceback自动生成文件名:
def _sys_name(): t = str(traceback.extract_stack()) b = True for x in os.listdir(case_dir): if x not in ["BaseCase.py", "__pycache__"]: if x in t: return x + "接口调用记录" + current_date() + ".csv" if b: print("request找不到sysname") print(t)
HTMLTestRunner
根据通用的版本,再参考网上一些现有的美化代码,综合了一下,根据自己需求做了改造。
近20交易日测试通过率
加了一个echarts,把最近20交易日的测试通过率,通过折线走势图的方式展示出来。监测系统稳定性。
数据存放和读取在data目录的csv文件中。
统计表格
按项目进行分组统计,增加测试说明一列,按颜色区别测试结果状态,可点击查看详细描述和错误信息。
同时优化了整体的样式效果。
排序:
# 按照通过率从小到大排序
passrate_value = [] for key in passrate: if key != 'total': passrate_value.append(float(passrate[key].replace('%', ''))) passrate_value.sort()
保存折线图数据:
today = datetime.datetime.now().strftime('%Y-%m-%d') if '--' not in names: # 跑单个系统不存 if dao_is_trade_date(today): # 非交易日不存 with open(self.rct20_path, "r") as f: # 读取数据 lines = csv.reader(f) lines = list(lines) for lin in lines: lin[0] = lin[0].replace('月', '-') lin[0] = lin[0].replace('日', '') rct_data = lines # print(rct_data) nowdate = datetime.datetime.now().strftime('%m-%d') # 如果有重复日期,先删 l = len(rct_data) while l != 0 and nowdate == rct_data[l - 1][0]: rct_data.pop(l - 1) l = len(rct_data) for pt in self.passrate_tl: n = pt[0] v = pt[1] row = [] row.append(str(nowdate)) row.append(str(n)) row.append(str(v).replace('%', '')) rct_data.append(row) # 只存近20条 row_20 = len(names) * 20 if len(rct_data) > row_20: # 超过20条 for i in range(0, len(names)): rct_data.pop(0) with open(self.rct20_path, 'w', newline='') as f: writer = csv.writer(f) writer.writerows(rct_data)
拼接折线图数据用于展示:
while ri < len(rct_data): # 遍历 ->s_data scan = [] while ri < len(rct_data) and rct_data[ri][0] == trade_date[di]: s_data[rct_data[ri][1]].append(rct_data[ri][2]) scan.append(rct_data[ri][1]) ri += 1 chg = list(set(names) ^ set(scan)) # 差集 for c in chg: s_data[c].append('--') # 增加/减少的项目,为'--' di += 1 series = [] # 系列序列 s_names = s_data.keys() for k in s_names: s = {} # 单个系列 s['name'] = k s['type'] = 'line' if s_data != {}: s['data'] = s_data[k] series.append(s)
这部分代码是很久之前写的了,代码应该是不够简洁、高效、规范滴,是可以优化滴。偷了懒没有重构了。
用例设计
测试类型 | 描述 |
---|---|
冒烟测试 | 所有接口写单独的test,确保调用正常。 |
全选测试 | 将所有参数尽可能多的全选上,调用接口。 一定程序上可以弥补结对测试的不足。 |
结对测试 | 如前文所述,关注两两组合的情况。 |
参数值,部分采用随机数。也视需求,从数据库或其他接口获取数据。
结束语
第一次写技术博客。
马上工作5年。
算是一个尝试吧。
接口自动化测试框架-AIM的更多相关文章
- 接口自动化测试框架-AIM3.0-开源+OOP
这是3.0了,从1.0到2.0直接跨越到3.0,就是这么随意. 3.0的关键词一是开源,源码地址为https://github.com/dongfanger/AIM,二是OOP. 随着python的发 ...
- 接口自动化测试框架-AIM2.0
跳转到3.0版本https://www.cnblogs.com/df888/p/12031649.html AIM是我用python搭建的第一款接口自动化测试框架,随着技术的提升,框架也在升级,故有了 ...
- 接口测试入门(4)--接口自动化测试框架 / list和map用法 / 随机选取新闻 (随机数生成) / 接口相关id映射
一.接口自动化测试框架 为了更好的组织测试方法,测试用例并且持续集成,我们选择了 java+testNG(测试用例组织)+gitlab(代码版本管理)+Jenkins(持续集成工具) 作为一整套的自 ...
- python版接口自动化测试框架源码完整版(requests + unittest)
python版接口自动化测试框架:https://gitee.com/UncleYong/my_rf [框架目录结构介绍] bin: 可执行文件,程序入口 conf: 配置文件 core: 核心文件 ...
- 接口自动化 [授客]基于python+Testlink+Jenkins实现的接口自动化测试框架V3.0
基于python+Testlink+Jenkins实现的接口自动化测试框架V3.0 by:授客 QQ:1033553122 博客:http://blog.sina.com.cn/ishou ...
- 接口自动化 基于python+Testlink+Jenkins实现的接口自动化测试框架[V2.0改进版]
基于python+Testlink+Jenkins实现的接口自动化测试框架[V2.0改进版] by:授客 QQ:1033553122 由于篇幅问题,,暂且采用网盘分享的形式: 下载地址: [授客] ...
- 基于python+Testlink+Jenkins实现的接口自动化测试框架V3.0
基于python+Testlink+Jenkins实现的接口自动化测试框架V3.0 目录 1. 开发环境2. 主要功能逻辑介绍3. 框架功能简介 4. 数据库的创建 5. 框架模块详细介绍6. Tes ...
- 【转】robot framework + python实现http接口自动化测试框架
前言 下周即将展开一个http接口测试的需求,刚刚完成的java类接口测试工作中,由于之前犯懒,没有提前搭建好自动化回归测试框架,以至于后期rd每修改一个bug,经常导致之前没有问题的case又产生了 ...
- 【python3+request】python3+requests接口自动化测试框架实例详解教程
转自:https://my.oschina.net/u/3041656/blog/820023 [python3+request]python3+requests接口自动化测试框架实例详解教程 前段时 ...
随机推荐
- tail 尾巴
tail用法:尾巴,取文件的最后N行,默认前10行, -n 2 取前2行-n 2,简写就是-2 -f 文件 跟踪一个文件尾部的时时变化. 克隆出一个窗口执行:循环脚本:for n in `seq 1 ...
- StringBuffer&StringBuilder类
0. 说明 1. 总体说明 当对字符串进行修改的时候,需要使用 StringBuffer 和 StringBuilder 类. 和 String 类不同的是,StringBuffer 和 String ...
- 【转】Mysql学习---MySQL悲观锁中的排它锁
[原文]https://www.toutiao.com/i6595305814087434760/ 悲观锁中的排它锁. 排它锁关键字:for update 特点:会锁住行或者表,防止其他事务进行修改操 ...
- Windows下文件检索的基本姿势
要点 使用FindFirstFile和FindNextFile两个WindowsAPI,并配合链表或队列存储文件夹序列. C++源码(链表存储) #include <iostream> # ...
- 解决Maven下载慢的问题
直接在pom.xml中添加阿里的镜像 <repositories> <repository> <id>aliyun</id> <name>a ...
- 51nod 1636 教育改革
题目链接 令f[i][j][k]为第i天选择的课程为j,设置作业为a[j]+k时的最大作业量. 那么f[i][j][k]可以由哪些状态转移而来?先把课程按复杂度排序,那么可以转移来的课程是f[i-1] ...
- java使用elasticsearch进行模糊查询-已在项目中实际应用
java使用elasticsearch进行模糊查询 使用环境上篇文章本人已书写过,需要maven坐标,ES连接工具类的请看上一篇文章,以下是内容是笔者在真实项目中运用总结而产生,并写的是主要方法和思路 ...
- JAVA基础|从Class.forName初始化数据库到SPI破坏双亲委托机制
代码托管在:https://github.com/fabe2ry/classloaderDemo 初始化数据库 如果你写过操作数据库的程序的话,可能会注意,有的代码会在程序的开头,有Class.for ...
- Alpha冲刺报告(2/12)(麻瓜制造者)
今日任务总结 燃尽图如下: 具体完成情况如下: 江郑: 今天:完成了商品需求的数据库的基本构建. 遇到的问题:对于php的ci框架不熟,操作原理不懂 明天:和队友进行数据库的对接 符天愉: 今天:完成 ...
- 一些node模块的学习思考
12月14日清单 1 readline模块 var readline = require("readline"); // input 是必须的,output是可选的 rl = re ...