【接口自动化】Python+Requests接口自动化测试框架搭建【三】
经过上两篇文章的讲解,我们已经完成接口自动化的基础框架,现在开始根据实际项目丰满起来。
在PyCharm中新建项目,项目工程结构如下:

config:配置文件夹,可以将一些全局变量放于配置文件中,方便调用。例如:URL地址、端口,开发如经常更换端口在配置文件中便可修改。

data:测试用例表格文件夹,存放测试用例.xls和读取写入excel表的文件。
demo:程序公共类文件夹,存放程序公共类,例如:POST/GET请求,获取Token等。
kit:相关测试工具,压缩、发送邮件。
main:程序运行主文件夹。
report:测试报告文件夹。
test_case:测试用例。
公司实际开发项目中,存在接口依赖,即Token。Token获取方法为登录后返回Token值,所以我们编写一个登录类获取Token,并将Token放置于config文件中,成为全局变量,等其他接口调用时,直接引用变量。
在demo中新建DemoMain请求方法公共类。
DemoMain.py
#!/usr/bin/env python # encoding: utf-8 ''' @author: GongYu @license: (C) Copyright 2020 @contact: gong_yu_1996@163.com @software: PyCharm @file: DemoMain.py @time: 2020/7/31 10:58 @desc: 公共方法主类 ''' import requests class RunMain: def __init__(self): pass @staticmethod def send_post(url,cookies,headers,params=None): try: res = requests.post(url=url,cookies=cookies,headers=headers,data=params) return res.status_code # 返回响应状态代码 except Exception as msg: return msg @staticmethod def send_get(url,cookies,headers,params=None,): try: res = requests.get(url=url,cookies=cookies,headers=headers,params=params,) return res.status_code # 返回响应状态代码 except Exception as msg: return msg def run_main(self, url,method,cookies=None,headers=None,params=None): if method == 'GET': res = self.send_get(url,cookies,headers,params) return res elif method == 'POST': res = self.send_post(url,cookies,headers,params) return res else: print('不支持的请求方式!')
CaseDemo.py 根据接口分开编写请求方法

实际开发中遇到的问题(仅为自己记录):
1.return返回值的问题:实际项目测试中我们不能只返回code状态码,因为接口测试中不能只凭返回状态码进行断言,我们测试判定中还应检查接口返回值,接口返回值应在开发提供接口文档已经注明。所以上述代码中我们应将返回值改为res。
2.因为一开始只考虑断言状态码的问题,所以导致多新建一个LoginDemo请求类,如返回值为res,此文件即可删除。
3.配置文件中可以参考Postman中多种参数的方式进行配置,可根据实际项目自己增加,极其方便。还可以配置数据库等信息,不再赘述。
data文件夹:

GetExcel.py:获取测试用例操作类
#!/usr/bin/env python # encoding: utf-8 ''' @author: GongYu @license: (C) Copyright 2020 @contact: gong_yu_1996@163.com @software: PyCharm @file: GetExcel.py @time: 2020/8/12 17:03 @desc:获取Excel表格数据 ''' import xlrd def get_excel_data(sheetName,idCol=0,bodyCol=7,repsCol=9): # 获取数据函数 dataList = [] # 生成一个空字典 workSheet = xlrd.open_workbook('../data/JDData.xls', formatting_info=True).sheet_by_name(sheetName) # 获取表格 endRow = workSheet.nrows # 获取有效工作行数 for one in range(1, endRow): # 循环获取 if workSheet.cell(one,12).value == 'Yes': # 判断用例是否执行 dataList.append((workSheet.cell(one, idCol).value,workSheet.cell(one, bodyCol).value, workSheet.cell(one, repsCol).value)) # 追加dataList else: pass return dataList
固定读取表格中的数据即:第1列,第8列,第10列数据,所以形参写死。
SetExcel.py:测试结果写入Excel表格
#!/usr/bin/env python # encoding: utf-8 ''' @author: GongYu @license: (C) Copyright 2020 @contact: gong_yu_1996@163.com @software: PyCharm @file: SetExcel.py @time: 2020/8/14 17:01 @desc: 写入Excel ''' import xlrd import json from xlutils import copy class CSetExcel(): def SetExcel(self,sheetName,infodata,one,Col=10): path = '../data/JDData.xls' workSheet = xlrd.open_workbook(path,formatting_info=True) New_workSheet = copy.copy(workSheet) # 复制表格 New_Sheet = New_workSheet.get_sheet(sheetName) # 获取表格名 New_Sheet.write(one,Col,json.dumps(infodata,ensure_ascii=False)) # 写入Excel New_workSheet.save(path) # 保存
此处坑:
1.New_Sheet.write(one,Col,json.dumps(infodata,ensure_ascii=False)) # 写入Excel
如不加ensure_ascii=False,写入Excel中中文会被转义unicode编码。json.dumps(infodata):接口返回值为字典类型(dict)转换成字符串类型写入excel。
2.执行方法前,记得关闭Excel表格。
Data.excel模板格式

此处坑:(MD,我也不知道我为啥这么多坑踩.........心累啊,前人种树后人乘凉,我先填为敬。)
编号一列单元格格式为文本,不要设置成数值,设置成数值会被Python取出后变为1.0(浮点型),然后导致的结果就是SetExcel.py根据编号写入数据时,无法识别1.0单元格在哪里,出现错误。
kit文件夹:存放测试报告压缩工具类以及发送邮件类

ZipTool.py 压缩文件工具类
#!/usr/bin/env python # encoding: utf-8 ''' @author: GongYu @license: (C) Copyright 2020 @contact: gong_yu_1996@163.com @software: PyCharm @file: ZipTool.py @time: 2020/8/19 9:52 @desc: 压缩文件夹工具 ''' import os import zipfile import shutil class FileZip(): def File(self,source_dir, output_filename):# 打包目录为zip文件(未压缩) if os.path.exists('../report/Report.zip') == True : # 判断文件是否存在 print("报告压缩文件存在!正在执行删除........") os.remove('../report/Report.zip') # 删除文件 print("删除成功!正在执行打包操作........") zipf = zipfile.ZipFile(output_filename, 'w') pre_len = len(os.path.dirname(source_dir)) for parent, dirnames, filenames in os.walk(source_dir): for filename in filenames: pathfile = os.path.join(parent, filename) arcname = pathfile[pre_len:].strip(os.path.sep) # 相对路径 zipf.write(pathfile, arcname) zipf.close() shutil.move('../main/Report.zip', '../report') # 移动文件 print('打包完成,正在发送报告......') else: print('正在执行打包操作......') zipf = zipfile.ZipFile(output_filename, 'w') pre_len = len(os.path.dirname(source_dir)) for parent, dirnames, filenames in os.walk(source_dir): for filename in filenames: pathfile = os.path.join(parent, filename) arcname = pathfile[pre_len:].strip(os.path.sep) zipf.write(pathfile, arcname) zipf.close() shutil.move('../main/Report.zip', '../report') print('打包完成,正在发送报告......')
EmailTool.py 发送邮件工具类
#!/usr/bin/env python # encoding: utf-8 ''' @author: GongYu @license: (C) Copyright 2020 @contact: gong_yu_1996@163.com @software: PyCharm @file: EmailTool.py @time: 2020/8/19 9:53 @desc: 发送邮件工具 ''' import smtplib import time from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from email.header import Header class SendEmail(): def Email(slef): # 第三方 SMTP 服务 mail_host = "smtp.163.com" # 设置服务器 mail_user = "gong_yu_1996@163.com" # 用户名 mail_pass = " " # 口令 sender = 'gong_yu_1996@163.com' receivers = ['gong_yu_1996@163.com','1196936134@qq.com'] # 接收邮件,可设置为你的QQ邮箱或者其他邮箱,多邮箱设置为数组 message = MIMEMultipart() message['From'] = Header("GongYu", 'utf-8') #message['To'] = Header("测试", 'utf-8') ReportTime = time.strftime("%Y-%m-%d %H:%M") subject = '['+ReportTime +']接口自动化测试报告' message['Subject'] = Header(subject, 'utf-8') # 邮件正文内容 NewTime = time.strftime("%Y-%m-%d %H:%M") message.attach(MIMEText('各位领导,同事:附件内容为接口自动化测试报告。测试时间为:'+NewTime+',请下载查看!', 'plain', 'utf-8')) # 附件 att1 = MIMEText(open('../data/Data.xls', 'rb').read(), 'base64', 'utf-8') att1["Content-Type"] = 'application/octet-stream' att1["Content-Disposition"] = 'attachment; filename="JDData.xls"' message.attach(att1) att2 = MIMEText(open('../report/Report.zip', 'rb').read(), 'base64', 'utf-8') att2["Content-Type"] = 'application/octet-stream' att2["Content-Disposition"] = 'attachment; filename="Report.zip"' message.attach(att2) try: smtpObj = smtplib.SMTP() smtpObj.connect(mail_host, 25) # 25 为 SMTP 端口号 smtpObj.login(mail_user, mail_pass) smtpObj.sendmail(sender, receivers, message.as_string()) print("邮件发送成功!") except smtplib.SMTPException: print("Error: 无法发送邮件")
下面我们编写Test_case.py 文件,放置于test_case文件夹下
Test_case.py
#!/usr/bin/env python # encoding: utf-8 ''' @author: GongYu @license: (C) Copyright 2020 @contact: gong_yu_1996@163.com @software: PyCharm @file: Test_test.py @time: 2020/8/13 9:25 @desc: 测试执行 ''' import json import pytest import allure from data.GetExcel import get_excel_data from data.SetExcel import CSetExcel from demo.CaseDemo import addapi @allure.feature('地址接口测试') class Testaddapi(): @allure.story('获取一级地址') @pytest.mark.parametrize('idData,infoData,resultdata',get_excel_data('1-获取一级地址')) def test_getProvince(self,idData,infoData,resultdata): Res = addapi().getProvince() CSetExcel().SetExcel('1-获取一级地址', Res.json(), json.loads(idData)) assert Res.status_code == 200 assert Res.json()['resultMessage'] == json.loads(resultdata)['resultMessage'] assert Res.json()['success'] == json.loads(resultdata)['success']
我们采用的是Pytest测试框架,使用allure输出测试报告。
到这里我们的测试框架就已经完成了,下面我们编写一个运行主类:TestMain.py 进行启动测试。
#!/usr/bin/env python # encoding: utf-8 ''' @author: GongYu @license: (C) Copyright 2020 @contact: gong_yu_1996@163.com @software: PyCharm @file: TestMain.py @time: 2020/8/13 10:32 @desc: 运行主类 ''' import shutil import pytest import os from kit.ZipTool import FileZip from kit.EmailTool import SendEmail if __name__ == '__main__': # 启动allure if os.path.exists('../report/xml') == True or os.path.exists('../report/html') == True: print("报告目录存在!正在执行删除........") shutil.rmtree(r'../report/xml') shutil.rmtree(r'../report/html') print("删除成功!正在执行测试用例........") pytest.main(['../test_case/Test_test.py', '-s', '--alluredir', '../report/xml']) # 生成测试报告文件 print('测试报告转换HTML.....') os.system('allure generate ../report/xml -o ../report/html') # 将测试报告文件转化为HTML FileZip().File('../report', 'Report.zip') SendEmail().Email() os.system('allure serve ../report/xml') # 运行测试报告文件 else: print('正在执行测试用例........') pytest.main(['../test_case/Test_test.py', '-s', '--alluredir', '../report/xml']) print('测试报告转换HTML.....') os.system('allure generate ../report/xml -o ../report/html') FileZip().File('../report', 'Report.zip') SendEmail().Email() os.system('allure serve ../report/xml')
下面我们运行试一下:
控制台输出:

Allure测试报告:
下面我们登录一下邮箱查看一下:


我们已经将测试结果加入附件发送到了负责人的邮箱,到此我们的自动化测试框架已经完成。最后还有一个日志功能还没实现,等找个时间再来补充吧。
新手上路,知识不足,如有纰漏错误,还请大神们指正,谢谢各位咯~~~
浙公网安备 33010602011771号