人人都能学好丨10分钟带你入门基于Python的接口自动化测试框架

项目背景
公司内部的软件采用B/S架构 , 目的是进行实验室的数据存储、分析、管理 。 大部分是数据的增删改查 , 但是由于还在开发阶段 , 所以UI的变化非常快 , 难以针对UI进行自动化测试 , 那样会消耗大量的精力与时间维护自动化脚本 , 对于小团队来说就得不偿失了 。 针对此种情况 , 选用接口测试较为有效 。
人人都能学好丨10分钟带你入门基于Python的接口自动化测试框架
文章图片
工具选择
针对接口测试的自动化工具也很多 , 例如SoupUI、Postman、robotframework , 甚至jmeter这样的性能测试工具都可以进行接口测试 。
robotframework测试框架有很多的第三方库可以使用 , 采用的是填表的方式进行 , 较容易上手 , 但是无法深入底层的了解客户端与服务器的交互过程 。 jmeter这样的专注性能测试的工具 , 进行接口测试 , 有点大材小用的感觉而且无法生成测试报告 。 但是这些工具灵活性不够 , 也不完全适用于被测系统 。
综上考虑 , 决定自己开发一个简单的框架 , 优点是足够灵活 , 可以随时根据需求进行变更 , 后台使用的是python+flask进行开发 , 此次选用python2.7.11进行框架的开发 , python开发的速度很快 , 且容易上手 , 丰富的第三方库 , 大大加快了开发速度和难度 。
框架思路
由于是框架 , 所以要考虑到框架的可重用性和可维护性 。 其次 , 需要考虑到测试人员编写测试用例的方便性 , 采用数据驱动的设计方式 , 将数据分层出来 , 与业务逻辑剥离 。 这样测试人员就可以通过数据文件专注的写测试用例 , 不用关注代码编写 , 提高了效率 。 此次框架采用基本的excel进行数据管理 。 通过对excel的读取获得数据 。
之后将测试的结果生成HTML格式的测试报告发送给相关开发人员 。
第三方库介绍
Requests
python中有许多针对http的库 , 例如自带的urllib2 , 但是自带的urllib2编写起来实在是太费精力 , 所以采用号称"HTTPforHumans"的requests库 。
xlrd
xlrd使得python可以方便的对excel文件进行读写操作 , 此次通过xlrd读取excel文件中的测试数据 。
以上第三方库都可以通过pip直接安装或者通过pypi下载源码包安装 。
模块介绍
get_conf:读取配置文件 , 获得邮件发送的配置信息 , 如smtpserver、receiver、sender等 。
md5Encode:部分数据采用md5加密后传输 , 所以需要把从excel读取的数据进行md5加密 。
sendMail:当测试完成后 , 将测试报告自动的发送给相关开发人员 。
runTest:此部分读取excel中的数据 , 调用下方的interfaceTest方法 , 保存interfaceTest返回的信息 。
interfaceTest:将runTest读取的excel数据作为入参 , 执行接口测试 , 并将后台返回的信息返回给runTest 。
Excel的文件格式如下图 , APIPurpose记录接口的名称 , APIHost记录主机地址 , RequestMethon记录请求方式 , 可以选择GET或者POST 。
RequestData就是构造的测试数据 , 这里需要注意其格式的书写 。
CheckPoint是检查点的设置 , 当获得数据后 , 需要跟检查点的数据进行比对 , 如果符合 , 说明测试成功 , 反之失败 。
配置文件的格式如下图:
人人都能学好丨10分钟带你入门基于Python的接口自动化测试框架
文章图片
在这里可以设置邮件发送人、接收者、smtp服务器地址以及用户名密码 。 需要根据实际情况进行改变 。
代码实现
Python
#通过自带的ConfigParser模块 , 读取邮件发送的配置文件 , 作为字典返回
importConfigParser
defget_conf():
conf_file=ConfigParser.ConfigParser()
conf_file.read(os.path.join(os.getcwd(),"conf.ini"))
conf={}
conf["sender"]=conf_file.get("email","sender")
conf["receiver"]=conf_file.get("email","receiver")
conf["smtpserver"]=conf_file.get("email","smtpserver")
conf["username"]=conf_file.get("email","username")
conf["password"]=conf_file.get("email","password")
returnconf
#此处使用python自带的logging模块 , 用来作为测试日志 , 记录测试中系统产生的信息 。
importlogging,os
log_file=os.path.join(os.getcwd(),"log/sas.log")
log_format="[%(asctime)s][%(levelname)s]%(message)s"
logging.basicConfig(format=log_format,filename=log_file,filemode="w",level=logging.DEBUG)
console=logging.StreamHandler()
console.setLevel(logging.DEBUG)
formatter=logging.Formatter(log_format)
console.setFormatter(formatter)
logging.getLogger("").addHandler(console)
#读取testcaseexcel文件 , 获取测试数据 , 调用interfaceTest方法 , 将结果保存至errorCase列表中 。
importxlrd,hashlib,json
defrunTest(testCaseFile):
testCaseFile=os.path.join(os.getcwd(),testCaseFile)
ifnotos.path.exists(testCaseFile):
logging.error("测试用例文件不存在!")
sys.exit()
testCase=xlrd.open_workbook(testCaseFile)
table=testCase.sheet_by_index(0)
errorCase=[]#用于保存接口返回的内容和HTTP状态码
s=None
foriinrange(1,table.nrows):
iftable.cell(i,9).vale.replace("","").replace(" ","")!="Yes":
continue
num=str(int(table.cell(i,0).value)).replace("","").replace(" ","")
api_purpose=table.cell(i,1).value.replace("","").replace(" ","")
api_host=table.cell(i,2).value.replace("","").replace(" ","")
request_method=table.cell(i,4).value.replace("","").replace(" ","")
request_data_type=table.cell(i,5).value.replace("","").replace(" ","")
request_data=https://pcff.toutiao.jxnews.com.cn/p/20200403/table.cell(i,6).value.replace("","").replace(" ","")
encryption=table.cell(i,7).value.replace("","").replace(" ","")
check_point=table.cell(i,8).value
ifencryption=="MD5":#如果数据采用md5加密 , 便先将数据加密
request_data=https://pcff.toutiao.jxnews.com.cn/p/20200403/json.loads(request_data)
request_data["pwd"]=md5Encode(request_data["pwd"])
status,resp,s=interfaceTest(num,api_purpose,api_host,request_url,request_data,check_point,request_methon,request_data_type,s)
ifstatus!=200orcheck_pointnotinresp:#如果状态码不为200或者返回值中没有检查点的内容 , 那么证明接口产生错误 , 保存错误信息 。
errorCase.append((num+""+api_purpose,str(status),"http://"+api_host+request_url,resp))
returnerrorCase
#接受runTest的传参 , 利用requests构造HTTP请求
importrequests
definterfaceTest(num,api_purpose,api_host,request_method,
request_data_type,request_data,check_point,s=None)
headers={"Content-Type":"application/x-www-form-urlencodedcharset=UTF-8",
"X-Requested-With":"XMLHttpRequest",
"Connection":"keep-alive",
"Referer":"http://"+api_host,
"User-Agent":"Mozilla/5.0(WindowsNT6.1WOW64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/49.0.2623.110Safari/537.36"
}
ifs==None:
s=requests.session()
ifrequest_method=="POST":
ifrequest_url!="/login":
r=s.post(url="http://"+api_host+request_url,data=https://pcff.toutiao.jxnews.com.cn/p/20200403/json.loads(request_data),headers=headers)#由于此处数据没有经过加密 , 所以需要把Json格式字符串解码转换成**Python对象**
elifrequest_url=="/login":
s=requests.session()
r=s.post(url="http://"+api_host+request_url,data=https://pcff.toutiao.jxnews.com.cn/p/20200403/request_data,headers=headers)#由于登录密码不能明文传输 , 采用MD5加密 , 在之前的代码中已经进行过json.loads()转换 , 所以此处不需要解码
else:
logging.error(num+""+api_purpose+"HTTP请求方法错误 , 请确认[RequestMethod]字段是否正确!!!")
s=None
return400,resp,s
status=r.status_code
resp=r.text
printresp
ifstatus==200:
ifre.search(check_point,str(r.text)):
logging.info(num+""+api_purpose+"成功 , "+str(status)+","+str(r.text))
returnstatus,resp,s
else:
logging.error(num+""+api_purpose+"失败!!! , ["+str(status)+"],"+str(r.text))
return200,resp,None
else:
logging.error(num+""+api_purpose+"失败!!! , ["+str(status)+"],"+str(r.text))
returnstatus,resp.decode("utf-8"),None
importhashlib
defmd5Encode(data):
hashobj=hashlib.md5()
hashobj.update(data.encode("utf-8"))
returnhashobj.hexdigest()
defsendMail(text):
mail_info=get_conf()
sender=mail_info["sender"]
receiver=mail_info["receiver"]
subject="[AutomationTest]接口自动化测试报告通知"
smtpserver=mail_info["smtpserver"]
username=mail_info["username"]
password=mail_info["password"]
msg=MIMEText(text,"html","utf-8")
msg["Subject"]=subject
msg["From"]=sender
msg["To"]="".join(receiver)
smtp=smtplib.SMTP()
smtp.connect(smtpserver)
smtp.login(username,password)
smtp.sendmail(sender,receiver,msg.as_string())
smtp.quit()
defmain():
errorTest=runTest("TestCase/TestCase.xlsx")
iflen(errorTest)>0:
html="接口自动化定期扫描 , 共有"+str(len(errorTest))+"个异常接口 , 列表如下:"+"
fortestinerrorTest:
html=html+"
sendMail(html)
if__name__=="__main__":
【人人都能学好丨10分钟带你入门基于Python的接口自动化测试框架】main()


    推荐阅读