python_接口自动化测试框架

Posted Jasongo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python_接口自动化测试框架相关的知识,希望对你有一定的参考价值。

本文总结分享介绍接口测试框架开发,环境使用python3+selenium3+unittest+ddt+requests测试框架及ddt数据驱动,采用Excel管理测试用例等集成测试数据功能,以及使用HTMLTestRunner来生成测试报告,目前有开源的poman、Jmeter等接口测试工具,为什么还要开发接口测试框架呢?因接口测试工具也有存在几点不足。

  • 测试数据不可控制。比如接口返回数据不可控,就无法自动断言接口返回的数据,不能断定是接口程序引起,还是测试数据变化引起的错误,所以需要做一些初始化测试数据。接口工具没有具备初始化测试数据功能,无法做到真正的接口测试自动化。
  • 无法测试加密接口。实际项目中,多数接口不是可以随便调用,一般情况无法摸拟和生成加密算法。如时间戳和MDB加密算法,一般接口工具无法摸拟。
  • 扩展能力不足。开源的接口测试工具无法实现扩展功能。比如,我们想生成不同格式的测试报告,想将测试报告发送到指定邮箱,又想让接口测试集成到CI中,做持续集成定时任务。

测试框架处理流程

 

 测试框架处理过程如下:

  1. 首先初始化清空数据库表的数据,向数据库插入测试数据;
  2. 调用被测试系统提供的接口,先数据驱动读取excel用例一行数据;
  3. 发送请求数据,根据传参数据,向数据库查询得到对应的数据;
  4. 将查询的结果组装成JSON格式的数据,同时根据返回的数据值与Excel的值对比判断,并写入结果至指定Excel测试用例表格;
  5. 通过单元测试框架断言接口返回的数据,并生成测试报告,最后把生成最新的测试报告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 = 发布会系统接口自动化测试报告
config.ini
 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()
mysql_db.py
 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},
28         {\'id\':3,\'realname\':\'Jams\',\'phone\':13511886603,\'email\':\'tom@mail.com\',\'sign\':0,\'event_id\':5},
29     ],
30 }
31 
32 # 测试数据插入表
33 def init_data():
34     DB().init_data(datas)
test_data.py
 1 #!/usr/bin/env python
 2 # _*_ coding:utf-8 _*_
 3 __author__ = \'YinJia\'
 4 
 5 import os,sys
 6 BASE_DIR = os.path.dirname(os.path.dirname(__file__))
 7 sys.path.append(BASE_DIR)
 8 
 9 # 配置文件
10 TEST_CONFIG =  os.path.join(BASE_DIR,"database","config.ini")
11 # 测试用例模板文件
12 SOURCE_FILE = os.path.join(BASE_DIR,"database","DemoAPITestCase.xlsx")
13 # excel测试用例结果文件
14 TARGET_FILE = os.path.join(BASE_DIR,"report","excelReport","DemoAPITestCase.xlsx")
15 # 测试用例报告
16 TEST_REPORT = os.path.join(BASE_DIR,"report")
17 # 测试用例程序文件
18 TEST_CASE = os.path.join(BASE_DIR,"testcase")
setting.py

程序核心模块

 1 #!/usr/bin/env python
 2 # _*_ coding:utf-8 _*_
 3 __author__ = \'YinJia\'
 4 
 5 import os
 6 
 7 def new_report(testreport):
 8     """
 9     生成最新的测试报告文件
10     :param testreport:
11     :return:返回文件
12     """
13     lists = os.listdir(testreport)
14     lists.sort(key=lambda fn: os.path.getmtime(testreport + "\\\\" + fn))
15     file_new = os.path.join(testreport,lists[-1])
16     return file_new
netReport.py
 1 #!/usr/bin/env python
 2 # _*_ coding:utf-8 _*_
 3 __author__ = \'YinJia\'
 4 
 5 import xlrd
 6 
 7 class ReadExcel():
 8     """读取excel文件数据"""
 9     def __init__(self,fileName, SheetName="Sheet1"):
10         self.data = xlrd.open_workbook(fileName)
11         self.table = self.data.sheet_by_name(SheetName)
12 
13         # 获取总行数、总列数
14         self.nrows = self.table.nrows
15         self.ncols = self.table.ncols
16     def read_data(self):
17         if self.nrows > 1:
18             # 获取第一行的内容,列表格式
19             keys = self.table.row_values(0)
20             listApiData = []
21             # 获取每一行的内容,列表格式
22             for col in range(1, self.nrows):
23                 values = self.table.row_values(col)
24                 # keys,values组合转换为字典
25                 api_dict = dict(zip(keys, values))
26                 listApiData.append(api_dict)
27             return listApiData
28         else:
29             print("表格是空数据!")
30             return None
readexcel.py
 1 #!/usr/bin/env python
 2 # _*_ coding:utf-8 _*_
 3 __author__ = \'YinJia\'
 4 
 5 import os,sys,json
 6 sys.path.append(os.path.dirname(os.path.dirname(__file__)))
 7 
 8 
 9 class SendRequests():
10     """发送请求数据"""
11     def sendRequests(self,s,apiData):
12         try:
13             #从读取的表格中获取响应的参数作为传递
14             method = apiData["method"]
15             url = apiData["url"]
16             if apiData["params"] == "":
17                 par = None
18             else:
19                 par = eval(apiData["params"])
20             if apiData["headers"] == "":
21                 h = None
22             else:
23                 h = eval(apiData["headers"])
24             if apiData["body"] == "":
25                 body_data = None
26             else:
27                 body_data = eval(apiData["body"])
28             type = apiData["type"]
29             v = False
30             if type == "data":
31                 body = body_data
32             elif type == "json":
33                 body = json.dumps(body_data)
34             else:
35                 body = body_data
36 
37             #发送请求
38             re = s.request(method=method,url=url,headers=h,params=par,data=body,verify=v)
39             return re
40         except Exception as e:
41             print(e)
sendrequests.py
 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 import smtplib
 9 from lib.newReport import new_report
10 import configparser
11 from email.mime.text import MIMEText
12 from email.mime.multipart import MIMEMultipart
13 
14 
15 def send_mail(file_new):
16     """
17     定义发送邮件
18     :param file_new:
19     :return: 成功:打印发送邮箱成功;失败:返回失败信息
20     """
21     f = open(file_new,\'rb\')
22     mail_body = f.read()
23     f.close()
24     #发送附件
25     con = configparser.ConfigParser()
26     con.read(setting.TEST_CONFIG,encoding=\'utf-8\')
27     report = new_report(setting.TEST_REPORT)
28     sendfile = open(report,\'rb\').read()
29     # --------- 读取config.ini配置文件 ---------------
30     HOST = con.get("user","HOST_SERVER")
31     SENDER = con.get("user","FROM")
32     RECEIVER = con.get("user","TOPython+requests+exce接口自动化测试框架

python接口自动化框架_初级

python+requests+unittest 搭建接口自动化测试框架

python写接口自动化框架

Python3+requests+unittest+log+excel+HTMLTestRunner+email框架接口自动化案例⑶——测试数据读取

pytest接口自动化测试框架 | 用python代码测试接口