基于Python的接口自动化测试框架

   目录

    前言:

     项目背景

  工具选择

  框架思路

  第三方库介绍

  代码实现

  不足之处


    前言:

Python是一种流行的编程语言,Python的易学性和易用性使得它成为编写接口自动化测试框架的理想选择。在Python中,有许多库可以帮助我们执行HTTP请求和解析JSON响应,例如Requests和Jsonpath等。此外,Python还具有出色的单元测试框架unittest和pytest,可以用于对接口进行单元测试和集成测试。

     项目背景

  公司内部的软件采用B/S架构,目的是进行实验室的数据存储、分析、管理。大部分是数据的增删改查,但是由于还在开发阶段,所以UI的变化非常快,难以针对UI进行自动化测试,那样会消耗大量的精力与时间维护自动化脚本,对于小团队来说就得不偿失了。针对此种情况,选用接口测试较为有效。

  工具选择

  针对接口测试的自动化工具也很多,例如Soup UI、Postman、robotframework,甚至jmeter这样的性能测试工具都可以进行接口测试。

  robot framework测试框架有很多的第三方库可以使用,采用的是填表的方式进行,较容易上手,但是无法深入底层的了解客户端与服务器的交互过程。jmeter这样的专注性能测试的工具,进行接口测试,有点大材小用的感觉而且无法生成测试报告。但是这些工具灵活性不够,也不完全适用于被测系统。

  综上考虑,决定自己开发一个简单的框架,优点是足够灵活,可以随时根据需求进行变更,后台使用的是python+flask进行开发,此次选用python 2.7.11进行框架的开发,python开发的速度很快,且容易上手,丰富的第三方库,大大加快了开发速度和难度。

  框架思路

  由于是框架,所以要考虑到框架的可重用性和可维护性。其次,需要考虑到测试人员编写测试用例的方便性,采用数据驱动的设计方式,将数据分层出来,与业务逻辑剥离。这样测试人员就可以通过数据文件专注的写测试用例,不用关注代码编写,提高了效率。此次框架采用基本的excel进行数据管理。通过对excel 的读取获得数据。

  之后将测试的结果生成HTML格式的测试报告发送给相关开发人员。

  第三方库介绍

  Requests

  python中有许多针对http的库,例如自带的urllib2,但是自带的urllib2编写起来实在是太费精力,所以采用号称"HTTP for Humans"的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的文件格式如下图,API Purpose记录接口的名称,API Host记录主机地址,Request Methon记录请求方式,可以选择GET或者POST。

  Request Data就是构造的测试数据,这里需要注意其格式的书写。

  Check Point是检查点的设置,当获得数据后,需要跟检查点的数据进行比对,如果符合,说明测试成功,反之失败。

  配置文件的格式如下图:

  在这里可以设置邮件发送人、接收者、smtp服务器地址以及用户名密码。需要根据实际情况进行改变。

  代码实现

#通过自带的ConfigParser模块,读取邮件发送的配置文件,作为字典返回
import ConfigParser
def get_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")
return conf
#此处使用python自带的logging模块,用来作为测试日志,记录测试中系统产生的信息。
import logging,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)
#读取testcase excel文件,获取测试数据,调用interfaceTest方法,将结果保存至errorCase列表中。
import xlrd,hashlib,json
def runTest(testCaseFile):
testCaseFile = os.path.join(os.getcwd(),testCaseFile)
if not os.path.exists(testCaseFile):
logging.error('测试用例文件不存在!')
sys.exit()
testCase = xlrd.open_workbook(testCaseFile)
table = testCase.sheet_by_index(0)
errorCase = []                #用于保存接口返回的内容和HTTP状态码
s = None
for i in range(1,table.nrows):
if table.cell(i, 9).vale.replace('\n','').replace('\r','') != 'Yes':
continue
num = str(int(table.cell(i, 0).value)).replace('\n','').replace('\r','')
api_purpose = table.cell(i, 1).value.replace('\n','').replace('\r','')
api_host = table.cell(i, 2).value.replace('\n','').replace('\r','')
request_method = table.cell(i, 4).value.replace('\n','').replace('\r','')
request_data_type = table.cell(i, 5).value.replace('\n','').replace('\r','')
request_data = table.cell(i, 6).value.replace('\n','').replace('\r','')
encryption = table.cell(i, 7).value.replace('\n','').replace('\r','')
check_point = table.cell(i, 8).value
if encryption == 'MD5':              #如果数据采用md5加密,便先将数据加密
request_data = 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)
if status != 200 or check_point not in resp:            #如果状态码不为200或者返回值中没有检查点的内容,那么证明接口产生错误,保存错误信息。
errorCase.append((num + ' ' + api_purpose, str(status), 'http://'+api_host+request_url, resp))
return errorCase
#接受runTest的传参,利用requests构造HTTP请求
import requests
def interfaceTest(num, api_purpose, api_host, request_method,
request_data_type, request_data, check_point, s=None)
headers = {'Content-Type' : 'application/x-www-form-urlencoded; charset=UTF-8',
'X-Requested-With' : 'XMLHttpRequest',
'Connection' : 'keep-alive',
'Referer' : 'http://' + api_host,
'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36'
}
if s == None:
s = requests.session()
if request_method == 'POST':
if request_url != '/login' :
r = s.post(url='http://'+api_host+request_url, data = json.loads(request_data), headers = headers)         #由于此处数据没有经过加密,所以需要把Json格式字符串解码转换成**Python对象**
elif request_url == '/login' :
s = requests.session()
r = s.post(url='http://'+api_host+request_url, data = request_data, headers = headers)          #由于登录密码不能明文传输,采用MD5加密,在之前的代码中已经进行过json.loads()转换,所以此处不需要解码
else:
logging.error(num + ' ' + api_purpose + '  HTTP请求方法错误,请确认[Request Method]字段是否正确!!!')
s = None
return 400, resp, s
status = r.status_code
resp = r.text
print resp
if status == 200 :
if re.search(check_point, str(r.text)):
logging.info(num + ' ' + api_purpose + ' 成功,' + str(status) + ', ' + str(r.text))
return status, resp, s
else:
logging.error(num + ' ' + api_purpose + ' 失败!!!,[' + str(status) + '], ' + str(r.text))
return 200, resp , None
else:
logging.error(num + ' ' + api_purpose + '  失败!!!,[' + str(status) + '],' + str(r.text))
return status, resp.decode('utf-8'), None
import hashlib
def md5Encode(data):
hashobj = hashlib.md5()
hashobj.update(data.encode('utf-8'))
return hashobj.hexdigest()
def sendMail(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()
def main():
errorTest = runTest('TestCase/TestCase.xlsx')
if len(errorTest) > 0:
html = '<html><body>接口自动化定期扫描,共有 ' + str(len(errorTest)) + ' 个异常接口,列表如下:' + '</p><table><tr><th style="width:100px;text-align:left">接口</th><th style="width:50px;text-align:left">状态</th><th style="width:200px;text-align:left">接口地址</th><th   style="text-align:left">接口返回值</th></tr>'
for test in errorTest:
html = html + '<tr><td style="text-align:left">' + test[0] + '</td><td style="text-align:left">' + test[1] + '</td><td style="text-align:left">' + test[2] + '</td><td style="text-align:left">' + test[3] + '</td></tr>'
sendMail(html)
if __name__ == '__main__':
main()

  由于所有的操作必须在系统登录之后进行,一开始没有注意到cookie这一点,每读取一个测试用例,都会新建一个session,导致无法维护上一次请求的cookie。然后将cookie添加入请求头中,但是第二个用例仍然无法执行成功。后来用fiddler抓包分析了一下,发现cookie的值竟然是"每一次操作后都会变化的!!!"

  所以只能通过session自动维护cookie。

  在interfaceTest函数中,返回三个值,分别是HTTP CODE,HTTP返回值与session。再将上一次请求的session作为入参传入interfaceTest函数中,在函数内部判断session是否存在,如果不为None,那么直接利用传入的session执行下一个用例,如果为None,那么新建一个session。

  不足之处

  1. 框架十分简陋,只是简单想法的实现,对于编码的细节没有完善。

  2. HTML的测试报告书写起来比较麻烦,可以考虑引入第三方库进行HTML测试报告的书写,将生成的HTML文件作为附件发送。

  3. 只是针对公司内部的软件,换用其他平台就不适用,需要修改源码。

 作为一位过来人也是希望大家少走一些弯路,希望能对你带来帮助。(WEB自动化测试、app自动化测试、接口自动化测试、持续集成、自动化测试开发、大厂面试真题、简历模板等等),相信能使你更好的进步!

留【自动化测试】即可【自动化测试交流】:574737577(备注ccc)icon-default.png?t=N4P3http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=2szVdJcy6VnqVi_zYhQd8aI9U5yfUv34&authKey=leQfP2SBsSV1%2FUzpd2OtJhdk%2F0SH%2FzEdi8uCVyM4q8w%2FHQEA1WUh3aqS9kyXZxUH&noverify=0&group_code=574737577

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/28440.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

淘宝拍照基于端云协同的视频流实时搜索实践

本文介绍了实时视频流的主体识别场景&#xff0c;未来实时搜将会融合图搜主链路并在XR场景发力&#xff0c;未来的场景我们取名为“元视界”&#xff08;MetaSight&#xff09; 引言 很多熟悉淘宝的用户知道&#xff0c;点击首页搜索框的相机icon&#xff0c;就可以使用淘宝拍照…

SpringBoot--日志

日志的作用&#xff1f; 记录用户登陆日志&#xff0c;方便分析用户是正常登陆还是恶意破解用户记录系统的操作日志&#xff0c;方便数据恢复和定位操作人记录程序的执行时间&#xff0c;方便为以后优化程序提供数据支持 日志是程序的重要组成部分&#xff0c;最重要的用途是…

Redis GEO地理位置信息的应用

Redis GEO地理位置信息的应用 Redis GEO概述应用场景Redis GEO命令GEO命令演示 Redis GEO实现附近人的功能基础类API接口接口实现执行测试 Redis GEO 概述 Redis的GEO操作是一种基于地理位置信息进行操作的功能。它使用经度和纬度坐标来表示地理位置&#xff0c;支持存储地理位…

Flutter 库:提升开发体验——Quick

Flutter 库&#xff1a;提升开发体验——Quick 文章目录 Flutter 库&#xff1a;提升开发体验——Quick一、概述1、简介2、功能3、官方资料4、思考 二、基本使用1、安装2、基本使用3、运行结果 三、List 列表扩展示例四、Map 映射扩展示例五、其它示例 一、概述 1、简介 Quic…

MySQL-索引详解(五)

♥️作者&#xff1a;小刘在C站 ♥️个人主页&#xff1a; 小刘主页 ♥️努力不一定有回报&#xff0c;但一定会有收获加油&#xff01;一起努力&#xff0c;共赴美好人生&#xff01; ♥️学习两年总结出的运维经验&#xff0c;以及思科模拟器全套网络实验教程。专栏&#xf…

设计模式(十三):行为型之模板方法模式

设计模式系列文章 设计模式(一)&#xff1a;创建型之单例模式 设计模式(二、三)&#xff1a;创建型之工厂方法和抽象工厂模式 设计模式(四)&#xff1a;创建型之原型模式 设计模式(五)&#xff1a;创建型之建造者模式 设计模式(六)&#xff1a;结构型之代理模式 设计模式…

微服务_Hystrix

在每个服务中引用该组件&#xff0c;监控当前组件。可被GateWay、Fegin集成。简介 作用&#xff1a;防止服务雪崩 Hystrix是一个由Netflix开源的容错框架&#xff0c;它主要用于分布式系统中的服务间通信。Hystrix通过在调用服务的过程中添加各种容错机制&#xff0c;来保护系…

助你更好的理解 Python 字典

助你更好的理解 Python 字典 字典是Python中的常用数据类型之一&#xff0c;可将数据存储在键/值对中&#xff0c;同 Java 中的 Map 相似。 1、什么是字典理解&#xff1f; 字典理解是创建字典的一种优雅简洁的方法。 字典理解优化 使用字典理解优化函数。 示例&#xff…

深入理解Linux虚拟内存管理(七)

系列文章目录 Linux 内核设计与实现 深入理解 Linux 内核 Linux 设备驱动程序 Linux设备驱动开发详解 深入理解Linux虚拟内存管理&#xff08;一&#xff09; 深入理解Linux虚拟内存管理&#xff08;二&#xff09; 深入理解Linux虚拟内存管理&#xff08;三&#xff09; 深入理…

chatgpt赋能python:Introduction

Introduction 在机器学习中&#xff0c;模型的训练是非常重要的步骤之一。模型训练意味着为数据拟合合适的参数&#xff0c;以便能够准确地预测未来的值。Python是一种功能强大的编程语言&#xff0c;提供许多库和框架来训练机器学习模型。在本文中&#xff0c;我们将探讨如何…

mysql 最常用的一些语句

1 数据库相关操作 CREATE DATABASE IF NOT EXISTS daily-test DEFAULT CHARSET utf8 COLLATE utf8_general_ci&#xff1b; drop database daily_test; use daily_test 具体操作如下图上所示&#xff1a; 2 mysql常用数据类型 MySQL 数据类型 | 菜鸟教程 3 数据库表相关操作…

CSS基础学习--13 Display(显示) 与 Visibility(可见性)

一、定义 display属性设置一个元素应如何显示 visibility属性指定一个元素应可见还是隐藏 二、隐藏元素 - display:none或visibility:hidden 隐藏一个元素可以通过把display属性设置为"none"&#xff0c;或把visibility属性设置为"hidden"。但是请注意&am…

chatgpt赋能python:Python怎么抢优惠券?优惠不再是梦想!

Python怎么抢优惠券&#xff1f;优惠不再是梦想&#xff01; 在如今的消费社会&#xff0c;优惠券已成为人们购物时追逐的目标。而优惠券的数量有限且抢手&#xff0c;往往仅能在短时间内领取&#xff0c;因此初次抢到心仪的优惠券可谓令人欣喜不已。而对于程序员们而言&#…

上线客流人数统计系统实现资源的最大化利用

在流量管理方面&#xff0c;智慧客流采集系统的应用可以帮助商家实现资源的最大化利用。通过对客流量数据的分析&#xff0c;商家可以准确把握客流量变化规律&#xff0c;进而制定出最优化的资源配置方案。 AI客流视觉监控 一、某汽车4S店智慧客流采集系统案例展示 以某汽车4S…

ESXi 7.0 U3m Dell (戴尔) 定制版 OEM Custom Installer CD

VMware ESXi 7.0 Update 3m - 领先的裸机 Hypervisor (All OEM Customized Installer CDs) ESXi 7.0 U3m Standard (标准版) ESXi 7.0 U3m Dell (戴尔) 定制版 OEM Custom Installer CD ESXi 7.0 U3m HPE (慧与) 定制版 OEM Custom Installer CD ESXi 7.0 U3m Lenovo (联想) 定…

python中变量与字符串详解!!

❄️作者介绍&#xff1a;奇妙的大歪❄️ &#x1f380;个人名言&#xff1a;但行前路&#xff0c;不负韶华&#xff01;&#x1f380; &#x1f43d;个人简介&#xff1a;云计算网络运维专业人员&#x1f43d; 前言 初学者经常会遇到的困惑是&#xff0c;看书上或者是听课都懂…

django中url和视图函数path re_path views.py

目录 url的定义url的格式django中的urldjango中的创建自己的urldjango访问测试django中的path动态django中的path动态案例django中的path动态类型django中的path动态案例-计算器django的正则路由re_path() url的定义 url 统一资源定位符 url 用来表示互联网上某个资源的地址 …

详解c++---set的介绍

目录标题 set容器的介绍set的构造函数insert函数的介绍find函数erase函数count函数lower_boundupper_boundmultiset set容器的介绍 set容器可以看成我们上一篇文章学习的K结构的搜索二叉树&#xff0c;所以set容器不仅可以存储数据&#xff0c;还可以对数据进行排序和去重&…

新项目之初性能测试工作如何前移?

最近刚接手一个新项目&#xff0c;在最开始的时候要求对这个项目做性能测试&#xff0c;产品经理也给不出性能需求&#xff0c;只因为这个项目是电商项目&#xff0c;可能会有高并发&#xff0c;秒杀的场景&#xff0c;所以产品经理要求我们对这个项目必须做性能测试&#xff0…

【Linux:进程间信号】

文章目录 1 生活角度的信号2 技术应用角度的信号3 信号的产生3.1 由系统调用向进程发信号3.1.1 signal3.1.2 kill3.1.3 raise 3.2 由软件条件产生信号3.3 硬件异常产生信号3.4 通过终端按键产生信号3.5 总结思考一下 4 信号的保存4.1信号其他相关常见概念4.2在内核中的表示4.3 …