python_接口自动化测试框架
本文总结分享介绍接口测试框架开发,环境使用python3+selenium3+unittest+ddt+requests测试框架及ddt数据驱动,采用Excel管理测试用例等集成测试数据功能,以及使用HTMLTestRunner来生成测试报告,目前有开源的poman、Jmeter等接口测试工具,为什么还要开发接口测试框架呢?因接口测试工具也有存在几点不足。
- 测试数据不可控制。比如接口返回数据不可控,就无法自动断言接口返回的数据,不能断定是接口程序引起,还是测试数据变化引起的错误,所以需要做一些初始化测试数据。接口工具没有具备初始化测试数据功能,无法做到真正的接口测试自动化。
- 无法测试加密接口。实际项目中,多数接口不是可以随便调用,一般情况无法摸拟和生成加密算法。如时间戳和MDB加密算法,一般接口工具无法摸拟。
- 扩展能力不足。开源的接口测试工具无法实现扩展功能。比如,我们想生成不同格式的测试报告,想将测试报告发送到指定邮箱,又想让接口测试集成到CI中,做持续集成定时任务。
测试框架处理流程
测试框架处理过程如下:
- 首先初始化清空数据库表的数据,向数据库插入测试数据;
- 调用被测试系统提供的接口,先数据驱动读取excel用例一行数据;
- 发送请求数据,根据传参数据,向数据库查询得到对应的数据;
- 将查询的结果组装成JSON格式的数据,同时根据返回的数据值与Excel的值对比判断,并写入结果至指定Excel测试用例表格;
- 通过单元测试框架断言接口返回的数据,并生成测试报告,最后把生成最新的测试报告HTML文件发送指定的邮箱。
测试框架结构目录介绍
目录结构介绍如下:
- config/: 文件路径配置
- database/: 测试用例模板文件及数据库和发送邮箱配置文件
- db_fixture/: 初始化接口测试数据
- lib/: 程序核心模块。包含有excel解析读写、发送邮箱、发送请求、生成最新测试报告文件
- package/: 存放第三方库包。如HTMLTestRunner,用于生成HTML格式测试报告
- report/: 生成接口自动化测试报告
- testcase/: 用于编写接口自动化测试用例
- run_demo.py: 执行所有接口测试用例的主程序
- GitHub项目地址: https://github.com/yingoja/DemoAPI
数据库封装

1 [tester] 2 name = Jason 3 4 [mysqlconf] 5 host = 127.0.0.1 6 port = 3306 7 user = root 8 password = 123456 9 db_name = guest 10 11 [user] 12 # 发送邮箱服务器 13 HOST_SERVER = smtp.163.com 14 # 邮件发件人 15 FROM = 111@163.com 16 # 邮件收件人 17 TO = 222@126.com 18 # 发送邮箱用户名/密码 19 user = aaa 20 password = aaa 21 # 邮件主题 22 SUBJECT = 发布会系统接口自动化测试报告

1 #!/usr/bin/env python 2 # _*_ coding:utf-8 _*_ 3 __author__ = 'YinJia' 4 5 import os,sys 6 sys.path.append(os.path.dirname(os.path.dirname(__file__))) 7 from config import setting 8 from pymysql import connect,cursors 9 from pymysql.err import OperationalError 10 import configparser as cparser 11 12 # --------- 读取config.ini配置文件 --------------- 13 cf = cparser.ConfigParser() 14 cf.read(setting.TEST_CONFIG,encoding='UTF-8') 15 host = cf.get("mysqlconf","host") 16 port = cf.get("mysqlconf","port") 17 user = cf.get("mysqlconf","user") 18 password = cf.get("mysqlconf","password") 19 db = cf.get("mysqlconf","db_name") 20 21 class DB: 22 """ 23 MySQL基本操作 24 """ 25 def __init__(self): 26 try: 27 # 连接数据库 28 self.conn = connect(host = host, 29 user = user, 30 password = password, 31 db = db, 32 charset = 'utf8mb4', 33 cursorclass = cursors.DictCursor 34 ) 35 except OperationalError as e: 36 print("Mysql Error %d: %s" % (e.args[0],e.args[1])) 37 38 # 清除表数据 39 def clear(self,table_name): 40 real_sql = "delete from " + table_name + ";" 41 with self.conn.cursor() as cursor: 42 # 取消表的外键约束 43 cursor.execute("SET FOREIGN_KEY_CHECKS=0;") 44 cursor.execute(real_sql) 45 self.conn.commit() 46 47 # 插入表数据 48 def insert(self, table_name, table_data): 49 for key in table_data: 50 table_data[key] = "'"+str(table_data[key])+"'" 51 key = ','.join(table_data.keys()) 52 value = ','.join(table_data.values()) 53 real_sql = "INSERT INTO " + table_name + " (" + key + ") VALUES (" + value + ")" 54 55 with self.conn.cursor() as cursor: 56 cursor.execute(real_sql) 57 self.conn.commit() 58 59 # 关闭数据库 60 def close(self): 61 self.conn.close() 62 63 # 初始化数据 64 def init_data(self, datas): 65 for table, data in datas.items(): 66 self.clear(table) 67 for d in data: 68 self.insert(table, d) 69 self.close()

1 #!/usr/bin/env python 2 # _*_ coding:utf-8 _*_ 3 __author__ = 'YinJia' 4 5 import sys, time, os 6 sys.path.append(os.path.dirname(os.path.dirname(__file__))) 7 from db_fixture.mysql_db import DB 8 9 # 定义过去时间 10 past_time = time.strftime("%Y-%m-%d %H:%M:%S",time.localtime(time.time()-100000)) 11 # 定义将来时间 12 future_time = time.strftime("%Y-%m-%d %H:%M:%S",time.localtime(time.time()+10000)) 13 14 # 创建测试数据 15 datas = { 16 # 发布会表数据 17 'sign_event':[ 18 {'id':1,'name':'红米Pro发布会','`limit`':2000,'status':1,'address':'北京会展中心','start_time':future_time}, 19 {'id':2,'name':'苹果iphon6发布会','`limit`':1000,'status':1,'address':'宝安体育馆','start_time':future_time}, 20 {'id':3,'name':'华为荣耀8发布会','`limit`':2000,'status':0,'address':'深圳福田会展中心','start_time':future_time}, 21 {'id':4,'name':'苹果iphon8发布会','`limit`':2000,'status':1,'address':'深圳湾体育中心','start_time':past_time}, 22 {'id':5,'name':'小米5发布会','`limit`':2000,'status':1,'address':'北京国家会议中心','start_time':future_time}, 23 ], 24 # 嘉宾表数据 25 'sign_guest':[ 26 {'id':1,'realname':'Tom','phone':13511886601,'email':'alen@mail.com','sign':0,'event_id':1}, 27 {'id':2,'realname':'Jason','phone':13511886602,'email':'sign@mail.com','sign':1,'event_id':1},