忘记从哪篇文章得到的框架了,后面还可以按需优化,整体还行吧,目前比较简单,不过也可以在项目中使用,下面记录下
xls格式的文件,jinrongcase.xls
python+request+excel/html_report+sendmail,
先看下结构(其实这里可以把7拿出来,建立一个testcase文件夹,将测试用例独立出来,再搞一个run文件夹专门放启动代码的脚本):
说明下:他的测试结果有两种呈现方式,一个是 在原测试用例excel中写入实际测试结果的excel文件:
还有一个就是html的一个report:
如果在项目中使用,个人建议后期把他的html的report优化下,改成用HTMLTestRunner(网上有,搜一下)这个文件输出的报告,会好看一点,比如下面这个(后期有时间或者有机会我会优化好提供出来):
自动化测试的思路:
处理数据→请求数据→断言结果→输出报告→邮件通知
处理数据,这个地方使用的是python的 wlrd库,读写excel文件
excelutils.py→excel用例读取,获取用例条数,用例内容,另外额外提供了一个写入excel的方法,为后期将测试结果写回到excel做准备,
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Author : zhh
# @Tel : 1871253****
# @Time : 2020/3/25 22:05
# @File : demo.py
import xlrd
from xlutils.copy import copy
'''
本部分是读取excel里面的测试用例。获取其中的内容
'''
class ExcelUtils:
# 初始化的函数
def __init__(self, excel_file="../dataconfig/jinrongcase.xls",table_index=0):
#打开工作簿
workbook = xlrd.open_workbook(excel_file)
# 获取对应的表
self.table = workbook.sheets()[table_index]
self.excel_file = excel_file
self.workbook = workbook
# 能够获取当前多少个测试用例
def getCaseCount(self):
return self.table.nrows # 表格的行数
# 获取单元格内容
def getExcelData(self, row, col):
return self.table.cell_value(row, col)
# 写入单元格内容
def writeExcelData(self, row, col, value):
#先重新打开工作簿
read_data = xlrd.open_workbook(self.excel_file)
#copy复制保留
write_data = copy(read_data)
#获取第一个工作表
sheet_data = write_data.get_sheet(0)
#写入内容
sheet_data.write(row, col, value)
#保存
write_data.save(self.excel_file)
# if __name__ == '__main__':
# excelUtils = ExcelUtils()
# print(excelUtils.getCaseCount())
# print(excelUtils.getExcelData(0, 5))
# excelUtils.writeExcelData(3, 12, "我我我")
varsutils.py →索引类,索引数字是对照excel表格的测试用例来定义的,主要方面后期数据二次处理时excel中各列数据的获取,
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Author : zhh
# @Tel : 1871253****
# @Time : 2020/3/25 22:05
# @File : demo.py
from selenium.webdriver.common.by import By
# 定义索引的工具类
class VarUtils:
# id的索引
ID = 0
# 请求名称的索引
REQUEST_NAME = 1
# 请求地址的索引
REQUEST_URL = 2
# 请求方式的索引
REQUEST_METHOD = 3
# 请求参数的索引
REQUEST_PARAMS = 4
# 请求头的索引
REQUEST_HEADERS = 5
# 预期结果的索引
EXPECT_RESULT = 6
# 实际结果的索引
ACTUAL_RESULT = 7
# 是否通过的索引
IS_PASSED = 8
datautils.py→数据的二次处理,工具类,详细的提取接口请求需要的数据,分类封装各种方法
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Author : zhh
# @Tel : 1871253****
# @Time : 2020/3/25 22:05
# @File : demo.py
import json
# 数据工具类
from common.excelutils import ExcelUtils
from common.varutils import VarUtils
class DataUtils:
def __init__(self):
# 用到excelUtils对象
self.excelutils = ExcelUtils()
# 获取用例id
def getCaseId(self, row):
return self.excelutils.getExcelData(row, VarUtils.ID)
# 获取用例名称
def getCaseName(self, row):
return self.excelutils.getExcelData(row, VarUtils.REQUEST_NAME)
# 获取请求方式
def getRequestMethod(self, row):
return self.excelutils.getExcelData(row, VarUtils.REQUEST_METHOD)
# 获取请求地址
def getRequestUrl(self, row):
return self.excelutils.getExcelData(row, VarUtils.REQUEST_URL)
# 获取请求参数
def getRequestParams(self, row):
param = self.excelutils.getExcelData(row, VarUtils.REQUEST_PARAMS)
if param != "":
return json.loads(self.excelutils.getExcelData(row, VarUtils.REQUEST_PARAMS))
else:
return {}
# 获取请求头
def getRequestHeaders(self, row):
result = self.excelutils.getExcelData(row, VarUtils.REQUEST_HEADERS)
if result == None or result == "" or result == "否":
return None
else:
return result
# 获取预期结果
def getExpectResult(self, row):
str = self.excelutils.getExcelData(row, VarUtils.EXPECT_RESULT)
return str
# 设置实际结果
def setActualResult(self, row, dict):
str = json.dumps(dict, indent=4, ensure_ascii=False, sort_keys=True)
self.excelutils.writeExcelData(row, VarUtils.ACTUAL_RESULT, str)
# 设置是否通过 boolean类型
def setIsPassed(self, row, flag):
if flag == True:
self.excelutils.writeExcelData(row, VarUtils.IS_PASSED, "通过")
else:
self.excelutils.writeExcelData(row, VarUtils.IS_PASSED, "不通过")
if __name__ == '__main__':
str = '{"atatus": "200","cata": "null","bsg": "哈哈"}'
# 通过loads将字符串转换成字典
dict = json.loads(str)
print(dict.get("status"))
# 将字典转换成json字符串
str = json.dumps(dict, indent=4, ensure_ascii=False, sort_keys=True)
print(str)
requestutils.py →请求接口的工具类,一个get请求方法,一个post 请求方法(如果还有其他请求方式可以自己添加方法),一个执行请求 的方法,注意get请求的参数是字符串拼接url,post传参是放到请求体的json串,最终返回的结果都转成json
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Author : zhh
# @Tel : 1871253****
# @Time : 2020/3/25 22:05
# @File : demo.py
import json
import requests
class RequestUtils(object):
# 执行get请求
def __doGet(self, url, params=None, headers=None):
result = {}
if headers is None:
result = requests.get(url, params=params).json()
else:
result = requests.get(url, params=params, headers=headers).json()
return result
# 执行post请求
def __doPost(self, url, data, headers=None):
# 判断是否有请求头
result = None
if headers == None:
result = requests.post(url, data=json.dumps(data)).json()
else:
result = requests.post(url, data=json.dumps(data), headers=headers).json()
return result
# 执行外界调用
def doRequest(self, url, method, data, headers):
if method == "GET":
return self.__doGet(url, params=data, headers=headers)
elif method == "POST":
return self.__doPost(url, data=data, headers=headers)
else:
raise Exception("没有声明请求方式,请在接口用例中声明")
# if __name__ == '__main__':
# requestutils = RequestUtils()
# result = requestutils.doRequest("http://127.0.0.1:8081/stest/user/login.action", "GET", {
# "password": "123",
# "username": "zhangsan"
# }, None)
# print(result)
reportutils.py→输出html的测试报告,有一说一这个很简陋,在项目中使用建议换成HtmlTestRunner.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Author : zhh
# @Tel : 1871253****
# @Time : 2020/3/25 22:05
# @File : demo.py
import time
class ReportUtils:
# 定义总用例个数
sum_case_count = 0
# 定义通过的用例个数
pass_case_count = 0
def export_report(self, list):
# 打开文件
filename = "../reports/" + time.strftime("%Y%m%d%H%M%S", time.localtime())+".html"
stream = open(file=filename, mode="w", encoding="UTF-8")
stream.write(
''
'自动化接口测试报告
'
'用例编号 '
'用例名称 url地址 是否通过 ')
for case in list:
# 获取编号id信息
id = case["id"]
# 获取用例名称
name = case["name"]
# 获取url地址
url = case["url"]
# 是否通过
is_pass = case["is_pass"]
is_pass_str = None
if is_pass == True:
is_pass_str = "通过"
else:
is_pass_str = "不通过"
stream.write('%s %s %s %s ' % (id, name, url, is_pass_str))
stream.write(
'总结 '
'总用例个数:%d个 通过了%d个'
'
' % (
self.sum_case_count,self.pass_case_count))
sendemail.py→发送邮件的工具类,写明邮件标题,邮件内容,和要发送的附件路径,然后指定要发送的人员邮箱(人员很多的话建议邮箱可以存在一个excel读取来获取),调用发送邮件方法即可
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Author : zhh
# @Tel : 1871253****
# @Time : 2020/3/25 22:05
# @File : demo.py
import smtplib
import os
from email.mime.text import MIMEText
import zmail
import importlib,sys
importlib.reload(sys)
class SendMail:
def get_new_report(self,test_url):
# 列举test_dir目录下的所有文件名,结果以列表的形式返回
lists = os.listdir(test_url)
# sort按key的关键字进行升序排列,lambda的入参fn为lists列表的元素,获取问价的最新修改时间,
# 所以最终以文件时间从小到大排序
# 最后对lists元素,按文件修改时间大小从小到大排序
lists.sort(key=lambda fn: os.path.getmtime(test_url + '\\' + fn))
# 获取最新文件的绝对路径,列表中最后一个值,文件夹+文件名
file_path = os.path.join(test_url, lists[-1])
return file_path
def sndMail(self, title, content_text, attachments):
# 附件路径
# 你的邮件内容
mail_content = {
'title': title, # 标题
'content_text': content_text, # 邮件内容文字
'attachments': attachments # 附件路径
}
# 使用你的邮件账户名和密码登录服务器
server = zmail.server('[email protected]', '测试结束')
# 多个接收邮箱,单个收件人的话,直接是receiver='[email protected]'
receiver = ['1871253****@163.com', '1679019***@qq.com']
# 发送邮件
server.send_mail(receiver, mail_content)
financialtest.py→写testcase,也是用了unittest框架,写用例,然后把用例执行结果生成测试报告,邮件发送
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Author : zhh
# @Tel : 1871253****
# @Time : 2020/3/25 22:05
# @File : demo.py
import unittest
import time
from common.datautils import DataUtils
from common.excelutils import ExcelUtils
from common.reportutils import ReportUtils
from common.requestutils import RequestUtils
from common.sendmail import SendMail
import importlib, sys
importlib.reload(sys)
class FinancialTest(unittest.TestCase):
def setUp(self):
# 定义三个工具类
self.dataUtils = DataUtils()
self.excelUtils = ExcelUtils()
self.requestUtils = RequestUtils()
# 定义报告工具类
self.reportUtils = ReportUtils()
self.SendMail = SendMail()
pass
def tearDown(self):
pass
def testA(self):
list = []
# 读出所有的接口测试用例
count = self.excelUtils.getCaseCount()
# 遍历所有的用例,执行
for row in range(1, count):
dict = {}
# 根据行获取需要的内容
# 根据行获取url
url = self.dataUtils.getRequestUrl(row)
# 获取请求方式
method = self.dataUtils.getRequestMethod(row)
# 获取请求参数
params = self.dataUtils.getRequestParams(row)
# 获取请求头
headers = self.dataUtils.getRequestHeaders(row)
# 获取预期结果
expetedResult = self.dataUtils.getExpectResult(row)
# 将用例信息封装到字典中
dict["id"] = row
dict["name"] = self.dataUtils.getCaseName(row)
dict["url"] = url
# 执行相应的请求
actualResult = self.requestUtils.doRequest(url, method=method, data=params, headers=headers)
# =====判断预期结果是否和实际结果一致====
errorcode = 0
errorcode = actualResult["error_code"]
actualMsg = actualResult["reason"]
if str(errorcode) in expetedResult and actualMsg in expetedResult:
print("---通过---")
dict["is_pass"] = True
self.dataUtils.setIsPassed(row, True)
# 通过的个数加一
self.reportUtils.pass_case_count += 1
else:
dict["is_pass"] = False
self.dataUtils.setIsPassed(row, False)
# 往表格中写入实际结果
self.dataUtils.setActualResult(row, actualResult)
# 将字典装到列表中
list.append(dict)
# 对总用例个数进行赋值
self.reportUtils.sum_case_count = count - 1
# 执行导出报告
self.reportUtils.export_report(list)
time.sleep(5)
# 找到最新的报告
file_path = self.SendMail.get_new_report(r"D:\pyproject\lenovo\reports")
# 发送邮件
self.SendMail.sndMail('接口自动化测试', '各位同事们好,这是接口测试结果,请查收', file_path)