接口自动化python
!/usr/bin/env python
coding=utf-8
Todo:接口自动化测试
Author:归根落叶
Blog:http://this.ispenn.com
import json
import http.client,mimetypes
from urllib.parse import urlencode
import random
import time
import re
import logging
import os,sys
try:
import xlrd
except:
os.system('pip install -U xlrd')
import xlrd
try:
from pyDes import *
except ImportError as e:
os.system('pip install -U pyDes --allow-external pyDes --allow-unverified pyDes')
from pyDes import *
import hashlib
import base64
import smtplib
from email.mime.text import MIMEText
log_file = os.path.join(os.getcwd(),'log/liveappapi.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)
获取并执行测试用例
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 = []
correlationDict = {}
correlationDict['${hashPassword}'] = hash1Encode('123456')
correlationDict['${session}'] = None
for i in range(1,table.nrows):
correlationDict['${randomEmail}'] = ''.join(random.sample('abcdefghijklmnopqrstuvwxyz',6)) + '@automation.test'
correlationDict['${randomTel}'] = '186' + str(random.randint(10000000,99999999))
correlationDict['${timestamp}'] = int(time.time())
if table.cell(i,10).value.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_url = table.cell(i,3).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
correlation = table.cell(i,9).value.replace('\n','').replace('\r','').split(';')
for key in correlationDict:
if request_url.find(key) > 0:
request_url = request_url.replace(key,str(correlationDict[key]))
if request_data_type == 'Form':
dataFile = request_data
if os.path.exists(dataFile):
fopen = open(dataFile,encoding='utf-8')
request_data = fopen.readline()
fopen.close()
for keyword in correlationDict:
if request_data.find(keyword) > 0:
request_data = request_data.replace(keyword,str(correlationDict[keyword]))
try:
if encryption == 'MD5':
request_data = json.loads(request_data)
status,md5 = getMD5(api_host,urlencode(request_data).replace("%27","%22"))
if status != 200:
logging.error(num + ' ' + api_purpose + "[ " + str(status) + " ], 获取md5验证码失败!!!")
continue
request_data = dict(request_data,**{"sign":md5.decode("utf-8")})
request_data = urlencode(request_data).replace("%27","%22")
elif encryption == 'DES':
request_data = json.loads(request_data)
request_data = urlencode({'param':encodePostStr(request_data)})
else:
request_data = urlencode(json.loads(request_data))
except Exception as e:
logging.error(num + ' ' + api_purpose + ' 请求的数据有误,请检查[Request Data]字段是否是标准的json格式字符串!')
continue
elif request_data_type == 'Data':
dataFile = request_data
if os.path.exists(dataFile):
fopen = open(dataFile,encoding='utf-8')
request_data = fopen.readline()
fopen.close()
for keyword in correlationDict:
if request_data.find(keyword) > 0:
request_data = request_data.replace(keyword,str(correlationDict[keyword]))
request_data = request_data.encode('utf-8')
elif request_data_type == 'File':
dataFile = request_data
if not os.path.exists(dataFile):
logging.error(num + ' ' + api_purpose + ' 文件路径配置无效,请检查[Request Data]字段配置的文件路径是否存在!!!')
continue
fopen = open(dataFile,'rb')
data = fopen.read()
fopen.close()
request_data = '''
------WebKitFormBoundaryDf9uRfwb8uzv1eNe
Content-Disposition:form-data;name="file";filename="%s"
Content-Type:
Content-Transfer-Encoding:binary
%s
------WebKitFormBoundaryDf9uRfwb8uzv1eNe--
''' % (os.path.basename(dataFile),data)
status,resp = interfaceTest(num,api_purpose,api_host,request_url,request_data,check_point,request_method,request_data_type,correlationDict['${session}'])
if status != 200:
errorCase.append((num + ' ' + api_purpose,str(status),'http://'+api_host+request_url,resp))
continue
for j in range(len(correlation)):
param = correlation[j].split('=')
if len(param) == 2:
if param[1] == '' or not re.search(r'^[',param[1]) or not re.search(r']$',param[1]):
logging.error(num + ' ' + api_purpose + ' 关联参数设置有误,请检查[Correlation]字段参数格式是否正确!!!')
continue
value = resp
for key in param[1][1:-1].split(']['):
try:
temp = value[int(key)]
except:
try:
temp = value[key]
except:
break
value = temp
correlationDict[param[0]] = value
return errorCase
接口测试
def interfaceTest(num,api_purpose,api_host,request_url,request_data,check_point,request_method,request_data_type,session):
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 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.134 Safari/537.36'}
if session is not None:
headers['Cookie'] = 'session=' + session
if request_data_type == 'File':
headers['Content-Type'] = 'multipart/form-data;boundary=----WebKitFormBoundaryDf9uRfwb8uzv1eNe;charset=UTF-8'
elif request_data_type == 'Data':
headers['Content-Type'] = 'text/plain; charset=UTF-8'
conn = http.client.HTTPConnection(api_host)
if request_method == 'POST':
conn.request('POST',request_url,request_data,headers=headers)
elif request_method == 'GET':
conn.request('GET',request_url+'?'+request_data,headers=headers)
else:
logging.error(num + ' ' + api_purpose + ' HTTP请求方法错误,请确认[Request Method]字段是否正确!!!')
return 400,request_method
response = conn.getresponse()
status = response.status
resp = response.read()
if status == 200:
resp = resp.decode('utf-8')
if re.search(check_point,str(resp)):
logging.info(num + ' ' + api_purpose + ' 成功, ' + str(status) + ', ' + str(resp))
return status,json.loads(resp)
else:
logging.error(num + ' ' + api_purpose + ' 失败!!!, [ ' + str(status) + ' ], ' + str(resp))
return 2001,resp
else:
logging.error(num + ' ' + api_purpose + ' 失败!!!, [ ' + str(status) + ' ], ' + str(resp))
return status,resp.decode('utf-8')
获取md5验证码
def getMD5(url,postData):
headers = {'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8',
'X-Requested-With':'XMLHttpRequest'}
conn = http.client.HTTPConnection('this.ismyhost.com')
conn.request('POST','/get_isignature',postData,headers=headers)
response = conn.getresponse()
return response.status,response.read()
hash1加密
def hash1Encode(codeStr):
hashobj = hashlib.sha1()
hashobj.update(codeStr.encode('utf-8'))
return hashobj.hexdigest()
DES加密
def desEncode(desStr):
k = des('secretKEY', padmode=PAD_PKCS5)
encodeStr = base64.b64encode(k.encrypt(json.dumps(desStr)))
return encodeStr
字典排序
def encodePostStr(postData):
keyDict = {'key':'secretKEY'}
mergeDict = dict(postData, **keyDict)
mergeDict = sorted(mergeDict.items())
postStr = ''
for i in mergeDict:
postStr = postStr + i[0] + '=' + i[1] + '&'
postStr = postStr[:-1]
hashobj = hashlib.sha1()
hashobj.update(postStr.encode('utf-8'))
token = hashobj.hexdigest()
postData['token'] = token
return desEncode(postData)
发送通知邮件
def sendMail(text):
sender = 'no-reply@myhost.cn'
receiver = ['penn@myhost.cn']
mailToCc = ['penn@myhost.cn']
subject = '[AutomantionTest]接口自动化测试报告通知'
smtpserver = 'smtp.exmail.qq.com'
username = 'no-reply@myhost.cn'
password = 'password'
msg = MIMEText(text,'html','utf-8')
msg['Subject'] = subject
msg['From'] = sender
msg['To'] = ';'.join(receiver)
msg['Cc'] = ';'.join(mailToCc)
smtp = smtplib.SMTP()
smtp.connect(smtpserver)
smtp.login(username, password)
smtp.sendmail(sender, receiver + mailToCc, msg.as_string())
smtp.quit()
def main():
errorTest = runTest('TestCase/TestCasePre.xlsx')
if len(errorTest) > 0:
html = '接口自动化定期扫描,共有 ' + str(len(errorTest)) + ' 个异常接口,列表如下:' + '
接口 | 状态 | 接口地址 | 接口返回值 |
---|---|---|---|
' + test[0] + ' | ' + test[1] + ' | ' + test[2] + ' | ' + test[3] + ' |
'
#sendMail(html)
if name == 'main':
main()
接口自动化python的更多相关文章
- 接口自动化-python unittest+requests+HTMLrunner
从2015年毕业入行软件测试,快满4年了,之前技术分享都在百度贴吧上面,现在正式开始在博客中记录工作技术,努力成长,加油 接口测试的步骤1.组装好该接口需要的参数数据2.使用get或post附带参数数 ...
- 接口自动化-python+requests+pytest+csv+yaml
本套代码和逻辑 是本人的劳动成果,如果有转载需要标注, 非常适合公司做项目的同学!!!小白也可以学哦! 1.项目目录 2.公共方法的封装 2.1如果不用配置文件 可以使用这个方法进行封装--但是有一 ...
- 2020年第二期《python接口自动化+测试开发》课程,已开学!
2020年第二期<python接口自动化+python测试开发>课程,12月15号开学! 主讲老师:上海-悠悠 上课方式:QQ群视频在线教学,方便交流 本期上课时间:12月15号-3月29 ...
- python接口自动化(单元测试方法)
一.环境搭建 python +unittest+ requests实现http请求的接口自动化 Python的优势:语法简洁优美, 功能强大, 标准库跟第三方库灰常强大,建议大家事先了解一下Pytho ...
- python+request接口自动化框架
python+request接口自动化框架搭建 1.数据准备2.用python获取Excel文件中测试用例数据3.通过requests测试接口4.根据接口返回的code值和Excel对比 但本章只讲整 ...
- Python接口自动化——soap协议传参的类型是ns0类型的要创建工厂方法纪要
1:在Python接口自动化中,对于soap协议的xml的请求我们可以使用Suds Client来实现,其soap协议传参的类型基本上是有2种: 第一种是传参,不需要再创建啥, 第二种就是ns0类型的 ...
- 转载:python + requests实现的接口自动化框架详细教程
转自https://my.oschina.net/u/3041656/blog/820023 摘要: python + requests实现的接口自动化框架详细教程 前段时间由于公司测试方向的转型,由 ...
- python接口自动化(十)--post请求四种传送正文方式(详解)
简介 post请求我在python接口自动化(八)--发送post请求的接口(详解)已经讲过一部分了,主要是发送一些较长的数据,还有就是数据比较安全等.我们要知道post请求四种传送正文方式首先需要先 ...
- python接口自动化(四)--接口测试工具介绍(详解)
简介 “工欲善其事必先利其器”,通过前边几篇文章的介绍,大家大致对接口有了进一步的认识.那么接下来让我们看看接口测试的工具有哪些. 目前,市场上有很多支持接口测试的工具.利用工具进行接口测试,能够提供 ...
随机推荐
- 配置开发环境2——eclipse配置
纯手动配置eclipse, Eclipse配置 配置工作空间的编码方式 General—Workspace:改成Other:UTF-8 配置property的编码方式 配置maven Window — ...
- netperf 网络性能测试
Netperf是一种网络性能的测量工具,主要针对基于TCP或UDP的传输.Netperf根据应用的不同,可以进行不同模式的网络性能测试,即批量数据传输(bulk data transfer)模式和请求 ...
- scanf,fscanf,sscanf的区别
scanf是从文件中读 sscanf是从字符串中读 scanf是从键盘输入中读 fread :以字节位计算长度,按照指定的长度和次数读取数据,遇到结尾或完成指定长度读取后停止.fscanf :格式 ...
- python里面的xlrd模块
♦python操作excel主要用到xlrd和xlwt这两个库,即xlrd是读excel,xlwt是写excel的库. 今天就先来说一下xlrd模块: 一.安装xlrd模块 ♦ 到python官网下载 ...
- [trick] 玩弄svn的目录结构
今天在使用svn进行版本管理时出现了一个小问题: 原本在s目录下有一个c目录,不知为何被删除了,而svn st命令并没有认为它消失,svn up命令也无法下载回来: 从另一个地方拷贝过来一个c,svn ...
- PS火焰文字制作
火焰文字制作: 最终效果 第一步: 新建图层,并输入文字(这里不做详细解说)
- Kattis之旅——Divisible Subsequences
Given a sequence of positive integers, count all contiguous subsequences (sometimes called substring ...
- navicat mysql导出数据 批量插入的形式
这里介绍的是mysql 相同服务器类型数据传输的高级设置 选中数据库后右键“ 转储SQL文件”默认导出的记录格式是一条条的,采用的是”完整插入语句”,格式如下 '); '); '); 这种格式保证了兼 ...
- JS使用onscroll、scrollTop实现图片懒加载
今天做到项目中的图片展示,由于每一页的图片数量都很多,因此需要为图片的展示设计一种懒加载的功能. 第一要做的当然就是给程序添加滚动监听事件. //触发拉取图片开关,保证正在拉取时不能再次触发 var ...
- android 颜色值参考,(有颜色图
) 2011-10-13 19:55:30| 分类: android | 标签:android颜色值|字号大中小 订阅 Android 常用RGB值以及中英文名称 颜 色 RGB值 英文名 中文名 ...