前言
接上一篇 文章 ,上一篇文章主要介绍了整体的思路流程及大致结构,这篇大致说一下主要代码。
结构介绍
如上一篇文章所说,代码主要分为common(公共部分)和testcase(测试用例)。
common部分主要是进行:
- Excel读写操作
- 数据库相关操作
- 校验并返回结果
- 基础日志模块
testcase部分主要是各个case:
- 逐行读取Excel
- 发送请求
- 将返回的结果写入Excel
部分代码介绍
个人觉得整体结构中比较核心的是common部分,testcase部分相关逻辑比较简单。
common部分介绍
- Excel相关操作
主要就是读写操作,读取数据供接口发送请求,并将结果写入表格。
getexceldata.py
读取Excel数据分为两种,一个是读取指定单元格的数值,一个是读取行数
以读取请求参数为例,其他相同,请求参数多一步json.loads()
def get_formdata(name,rows):
'''
读取请求参数
:param name: sheet名称
:param rows: 行
:return:
'''
alldata=xlrd.open_workbook(file)
sheet = alldata.sheet_by_name(name)
value = sheet.cell(rows,6).value
if value == '':
return value
else:
return json.loads(value)
def get_nrows(name):
'''
读取行数
:param name: sheet名称
:return:
'''
alldata=xlrd.open_workbook(file)
sheet = alldata.sheet_by_name(name)
nrows = sheet.nrows
return nrows
setexceldata.py
以写入结果为例,列固定死,根据结果的不同设置对应的style
绿色 pass
红色 fail
黄色 not execute
def set_content(sheetnum,rows,content):
newWb=set_data()
newWs = newWb.get_sheet(sheetnum)
if len(content)>10000:
newWs.write(rows,12,content[:10000])
else:
newWs.write(rows,12,content)
newWb.save(file)
def set_result(sheetnum,rows,content):
'''
写测试结果pass 还是fail
:param sheetnum: sheet index
:param rows: 行
:param content: pass or fail or not execute
:return:
'''
newWb=set_data()
newWs = newWb.get_sheet(sheetnum)
stylered = xlwt.easyxf('pattern: pattern solid, fore_color red;')
stylegreen = xlwt.easyxf('pattern: pattern solid, fore_color green;')
styleyellow = xlwt.easyxf('pattern: pattern solid, fore_color yellow;')
if content == 'pass':
newWs.write(rows,13,content,stylegreen)
newWb.save(file)
elif content == 'fail':
newWs.write(rows,13,content,stylered)
newWb.save(file)
elif content == 'not execute':
newWs.write(rows,13,content,styleyellow)
newWb.save(file)
其他同这个或者更简单,只是列值不一样
备注:写入Excel有长度限制,所以在写入content的时候,加了截取字符串的操作
- 数据库相关操作
我司用的psg数据库,其他数据库操作类似。
分为两部分,一个connect_DB 一个check_DB
connect_DB.py
class DB :
def __init__(self):
try:
self.conn = psycopg2.connect(host= host ,
user=user,
port=port,
password=password,
database=db,
)
except Exception as e:
print e
def select(self,sql):
cusor = self.conn.cursor()
cusor.execute(sql)
rows = cusor.fetchall()
# for row in rows:
# print row[0]
return rows[0][0]
def close(self):
self.conn.close()
连接数据的一些参数host、user、port、password、db等写在配置文件config.ini中
check_DB.py
def check(name,rows):
'''
查询sql检查
:param name:sheetname
:param rows: 行
:return:
'''
execute = int(get.get_data(name,rows,7))
if execute == 0:
return ('pass','')
elif execute == 1:
sql = sql=get.get_data(name,rows,8)
actual_result = db.DB().select(sql)
expext_result = get.get_data(name,rows,9)
if actual_result == expext_result:
return ('pass',actual_result)
else:
return ('fail',actual_result)
读取Excel的值,如果进行sql校验,就执行,并返回sql执行的结果及校验结果
- 校验部分
校验分为3个流程,同时满足:- status_code = 200
- sql校验通过
- 返回content正则匹配通过
三个条件则判定为pass,否则就是fail
check_all.py
def checkall(sheetname,i,code,content):
'''
检查结果1.status_code 2.db校验 3.content正则匹配
:param self:
:param i: 行
:param code:
:param content:
:return:
'''
#判断结果是pass还是fail
if int(code) == 200 :
if checkdb.check(sheetname,i)[0] == 'pass':
print re.search(str(get.get_data(sheetname,i,10)),content)!=None
if re.search(str(get.get_data(sheetname,i,10)),content)!=None:
return 'pass'
elif re.search(get.get_data(sheetname,i,10),content) is None:
return 'fail'
else:
return 'fail'
else:
return 'fail'
testcase部分介绍
testcase部分,目前是一个模块一个用例,以商品模块为例,代码如下:
- 从配置文件中读取url
- 逐行进行数据读取
- 根据读取的数据发送请求
- 调用check_all判定结果
- 将结果写入Excel中
test_pd.py
class Pd(unittest.TestCase):
def test_pd(self):
cookie = test_login.login()
common_url=conf.ReadConfig().getloginConfigValue('url')
for i in range(int(get.get_nrows('pd'))-1):
# 判断是否执行
if int(get.get_data('pd',i+1,4))== 1:
login_url=get.get_data('pd',i+1,2)
url = common_url + login_url
data = get.get_formdata('pd',i+1)
header = {"Content-Type": "application/x-www-form-urlencoded","Cookie":cookie}
global r
print url
if get.get_data('pd',i+1,3) == 'post':
r=requests.post(url=url,headers=header,data=data)
if checkall.checkall('pd',i+1,r.status_code,r.content) == 'pass':
set.set_result(1,i+1,'pass')
elif checkall.checkall('pd',i+1,r.status_code,r.content) == 'fail':
set.set_result(1,i+1,'fail')
set.set_statuscode(1,i+1,r.status_code)
set.set_content(1,i+1,r.content.decode('UTF-8'))
set.set_sql(1,i+1,checkdb.check('pd',i+1)[1])
elif get.get_data('pd',i+1,3) == 'get':
r=requests.get(url=url,headers=header,data=data)
if checkall.checkall('pd',i+1,r.status_code,r.content) == 'pass':
set.set_result(1,i+1,'pass')
elif checkall.checkall('pd',i+1,r.status_code,r.content) == 'fail':
set.set_result(1,i+1,'fail')
set.set_statuscode(1,i+1,r.status_code)
set.set_content(1,i+1,r.content.decode('UTF-8'))
set.set_sql(1,i+1,checkdb.check('pd',i+1)[1])
elif int(get.get_data('pd',i+1,4))== 0:
print 'not execute'
set.set_result(1,i+1,'not execute')
if __name__ == "__main__":
Pd()
执行所有用例,用的是
test_runner.py
将需要执行的用例导入即可
from testcase.test_cm import Cm
from testcase.test_pd import Pd
def testsuit():
suite = unittest.TestSuite()
suite.addTests([unittest.defaultTestLoader.loadTestsFromTestCase(Cm),
unittest.defaultTestLoader.loadTestsFromTestCase(Pd),
])
runner = unittest.TextTestRunner(verbosity=2)
runner.run(suite)
if __name__ =="__main__":
testsuit()
以上所有,代码部分介绍结束
思考
一点小思考,这套模型主要试用与一些基础接口测试,如基础的查询、修改等
如果遇到一些业务上的强依赖,如新增一个订单,一个接口需要调用上一个订单会的值,这种下一个接口依赖上一个接口的,就不能用在一个for 循环中逐行读取数据,在发送请求了。
目前来看,个人觉得有下面几个缺陷:
- 报告的展示,批量执行时结果可能不太直观(这个可以后期优化,依赖Excel,直接生成饼状图等等)
- 缺少通知与失败重新跑机制(通知可以后续加上邮件,失败重跑也可以加上判断,fail重新执行一次)
- 对用例设计要求较高,由于是直接读取的Excel表格,如果表格数据出错,可能就会导致用例失败等情况
还有其他一些缺陷吧,欢迎有想法的小伙伴批评指正。
附上 Github地址,欢迎拍砖!