写点什么

python+requests+excel+unittest+ddt 接口自动化数据驱动并生成 html 报告 (优化版)

作者:虫无涯
  • 2023-02-24
    陕西
  • 本文字数:4255 字

    阅读完需:约 14 分钟

本文章内容是基于上海-悠悠的版本,进行了优化,增加了部分内容,详细请查阅下文。

1、原文链接

python+requests+excel+unittest+ddt接口自动化数据驱动并生成html报告

2、修改前后框架区别

修改前:



修改后:


3、主要修改内容

  • 增加:token 关联(token 获取和保存)

  • 增加:cookie 关联(cookie 获取和保存)

  • 增加:发送邮件(使用 SMTP)

  • 修改:HTML 报告模板中的样式和 ddt 用例的标题

  • 增加:logo 日志

4、详细修改内容说明

4.1、增加 token 关联

4.1.1、token 获取 get_token.py
import jsonimport requestsfrom common.operation_json import OperetionJson
class OperationHeader:
def __init__(self, response): # self.response = json.loads(response) self.response = response
def get_response_token(self): ''' 获取登录返回的token ''' token = {"data":{"token":self.response['data']['token']}} #token = {"token": self.response['data']['token']} return token
def write_token(self): op_json = OperetionJson() op_json.write_data(self.get_response_token())
def get_response_msg(self): reponse_msg = {"msg":self.response['msg']} #print("reponse_msg:", reponse_msg) return reponse_msg
复制代码
4.1.2、token 保存 operation_json.py
#coding:utf-8import jsonclass OperetionJson:
def __init__(self,file_path=None): if file_path == None: self.file_path = '../case/cookie.json' else: self.file_path = file_path self.data = self.read_data()
#读取json文件 def read_data(self): with open(self.file_path, 'r', encoding='utf-8') as fp: data1 = fp.read() if len(data1) > 0: data = json.loads(data1) else: data = {} return data
#根据关键字获取数据 def get_data(self,id): print(type(self.data)) return self.data[id]
#写json def write_data(self,data): with open('../case/token.json','w') as fp: fp.truncate() # 先清空之前的数据,再写入,这样每次登录的token都是不一样的 fp.write(json.dumps(data))
复制代码
4.1.3、token 的读取 base_api.py

在原代码中加入 token 的读取,即把 token 加入到 heasers 中


 # 请求头部headers    try:        headers = eval(testdata["headers"])        if testdata["token"] == "yes":            op_json = OperetionJson("../case/token.json")            token = op_json.get_data('data')            headers = dict(headers, **token)        print("请求头部:", headers)        log.info("请求头部:", headers)    except:        headers = None
复制代码

4.2、增加 cookie 关联

实现逻辑和获取 token 一模一样

4.2.1、cookie 获取 get_token.py

直接在获取 token 的 get_token.py 中加入,而这里的 token 格式需要根据自己的业务修改


    def get_response_cookie(self):        cookie1 = requests.utils.dict_from_cookiejar(self.response.cookies)        cookie = {"data":{"gfsessionid":cookie1["gfsessionid"]}}        # {"data": {"token": self.response['data']['token']}}        print("cookie:", cookie)        return cookie    def write_cookie(self):        op = OperetionJson()        op.write_mydata(self.get_response_cookie())
复制代码
4.2.2、cookie 保存 operation_json.py

直接在 operation_json.py 中加入


    def write_mydata(self,data):        with open('../case/cookie.json','w') as fp:            fp.truncate()  # 先清空之前的数据,再写入,这样每次登录的token都是不一样的            fp.write(json.dumps(data))
复制代码
4.2.3、cookie 的读取 base_api.py

直接在 base_api.py 中加入


    try:        headers = eval(testdata["headers"])        if testdata["cookie"] == "yes":            op_json = OperetionJson("../case/cookie.json")            token1 = op_json.get_data('data')            headers = dict(headers, **token1)        print("请求头部:", headers)        log.info("请求头部:", headers)    except:        headers = None
复制代码

4.3、增加邮件服务

4.3.1、邮件服务封装 send_mail.py
#coding=utf-8from email.mime.text import MIMETextimport timeimport smtplibimport getpassfrom email.mime.multipart import MIMEMultipartfrom email.mime.text import MIMETextfrom email.mime.base import MIMEBasefrom email import encodersimport emailimport os
def sendmain(file_path,mail_to = 'xxxxx@126.com'): mail_from = 'yyyyy@126.com' f = open(file_path,'rb') mail_body=f.read() f.close() #msg = email.MIMEMultipart.MIMEMultipart() msg = MIMEMultipart()
# 构造MIMEBase对象做为文件附件内容并附加到根容器 contype = 'application/octet-stream' maintype, subtype = contype.split('/', 1) ## 读入文件内容并格式化 data = open(file_path, 'rb') #file_msg = email.MIMEBase.MIMEBase(maintype, subtype) file_msg = MIMEBase(maintype, subtype) file_msg.set_payload(data.read( )) data.close( ) #email.Encoders.encode_base64(file_msg) encoders.encode_base64(file_msg) ## 设置附件头 basename = os.path.basename(file_path) file_msg.add_header('Content-Disposition', 'attachment', filename = basename) msg.attach(file_msg) print(u'msg 附件添加成功') msg1 = MIMEText(mail_body,_subtype='html',_charset='utf-8') msg.attach(msg1) if isinstance(mail_to,str): msg['To'] = mail_to else: msg['To'] = ','.join(mail_to) msg['From'] = mail_from msg['Subject'] = u'xxxxxxxxx接口自动化测试' # 邮件标题 msg['date']=time.strftime('%Y-%m-%d-%H_%M_%S') print(msg['date'])
smtp = smtplib.SMTP() smtp.connect('smtp.126.com') smtp.login('yyyyyy@126.com','aaaaaaaaaa') # 这里的密码是邮件第三方客户端认证密码 smtp.sendmail(mail_from, mail_to, msg.as_string()) smtp.quit() print('email has send out !')'''if __name__=='__main__': sendmain('../report/2017-08-18-10_18_57_result.html')'''
复制代码
4.3.2、邮件调用 run_this.py

直接在主函数入口中调用


sendmain(htmlreport, mail_to=['hhhhhhhh@126.com', 'jjjjjj@126.com', 'uuuuuu@126.com']) #多个收件人的话,直接在列表中,用,号隔开即可
复制代码

4.4、修改 html 报告模板

4.4.1、修改报告中用例的标题,修改 ddt 源码

①原报告用例的标题:因为使用 ddt,所以 ddt 格式中用例标题是 test_api_数字开头的用例名称,如果要自定义需要修改 ddt 源码



②修改后的报告标题:



③ 如何修改?可以参考之前的博文:unittest中使用ddt后生成的测试报告名称如何修改?(如test_api_0修改成test_api_0_titile)


def mk_test_name(name, value, index=0):    """    Generate a new name for a test case.
It will take the original test name and append an ordinal index and a string representation of the value, and convert the result into a valid python identifier by replacing extraneous characters with ``_``.
We avoid doing str(value) if dealing with non-trivial values. The problem is possible different names with different runs, e.g. different order of dictionary keys (see PYTHONHASHSEED) or dealing with mock objects. Trivial scalar values are passed as is.
A "trivial" value is a plain scalar, or a tuple or list consisting only of trivial values. """
# Add zeros before index to keep order
index = "{0:0{1}}".format(index + 1, index_len, ) if not is_trivial(value) and type(value) is not dict: # 增加的地方,增加value的字典判断
return "{0}_{1}_{2}".format(name, index, value.name) # 修改的地方,增加返回的值 if type(value) is dict: # 增加的地方 try: # 增加的地方 value = value["name"] + "_" + value["function"] # 增加的地方,name和function必须是execl用例中整正存在的表头,这里我是把两个表头合并了(name是我表格中接口的名称,function是表格中接口的功能描述) except: # 增加的地方 return "{0}_{1}".format(name.index) # 增加的地方 try: value = str(value) except UnicodeEncodeError: # fallback for python2 value = value.encode('ascii', 'backslashreplace') test_name = "{0}_{1}_{2}".format(name, index, value) # 修改的地方 return re.sub(r'\W|^(?=\d)', '_', test_name)
复制代码
4.4.2、增加用例执行人

在 HTMLTestRunner.py 中加入如下,即获取当前用例执行的负载机的用户名


 DEFAULT_TESTER = getpass.getuser()
复制代码

4.5、增加 log 日志

4.5.1、在框架入口中直接加入 run_this.py
# LOG日志记录    logging.basicConfig(level=logging.DEBUG,                        format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',                        datefmt='%a, %d %b %Y %H:%M:%S',                        filename=log_path + '/' + now + r"result.log",                        filemode='w')    logger = logging.getLogger()    logger.info(all_case)
复制代码


详细可以参考之前的博文:Unittest接口测试生成报告和日志方法

4.5.2、在其它模块中直接使用即可
log = logging.getLogger()log.info("请求头部:", headers)
复制代码

5、其它截图

log 截图:



测试报告:



邮件:



发布于: 刚刚阅读数: 5
用户头像

虫无涯

关注

专注测试领域各种技术研究、分享和交流~ 2019-12-11 加入

CSDN测试领域优质创作者 | CSDN博客专家 | 阿里云专家博主 | 华为云享专家 | 51CTO专家博主

评论

发布
暂无评论
python+requests+excel+unittest+ddt接口自动化数据驱动并生成html报告(优化版)_Python_虫无涯_InfoQ写作社区