草庐IT

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

虫无涯N 2023-03-28 原文
本文章内容是基于上海-悠悠的版本,进行了优化,增加了部分内容,详细请查阅下文。 (目录)

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 json import requests from 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-8 import json class 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-8 from email.mime.text import MIMEText import time import smtplib import getpass from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from email.mime.base import MIMEBase from email import encoders import email import 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__0titile)

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截图: 测试报告:

邮件:

有关python+requests+excel+unittest+ddt接口自动化数据驱动并生成html报告(优化版)的更多相关文章

  1. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  2. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  3. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  4. ruby - 在 jRuby 中使用 'fork' 生成进程的替代方案? - 2

    在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',

  5. ruby - 如何使用 Ruby aws/s3 Gem 生成安全 URL 以从 s3 下载文件 - 2

    我正在编写一个小脚本来定位aws存储桶中的特定文件,并创建一个临时验证的url以发送给同事。(理想情况下,这将创建类似于在控制台上右键单击存储桶中的文件并复制链接地址的结果)。我研究过回形针,它似乎不符合这个标准,但我可能只是不知道它的全部功能。我尝试了以下方法:defauthenticated_url(file_name,bucket)AWS::S3::S3Object.url_for(file_name,bucket,:secure=>true,:expires=>20*60)end产生这种类型的结果:...-1.amazonaws.com/file_path/file.zip.A

  6. ruby-on-rails - Rails HTML 请求渲染 JSON - 2

    在我的Controller中,我通过以下方式在我的index方法中支持HTML和JSON:respond_todo|format|format.htmlformat.json{renderjson:@user}end在浏览器中拉起它时,它会自然地以HTML呈现。但是,当我对/user资源进行内容类型为application/json的curl调用时(因为它是索引方法),我仍然将HTML作为响应。如何获取JSON作为响应?我还需要说明什么? 最佳答案 您应该将.json附加到请求的url,提供的格式在routes.rb的路径中定义。这

  7. ruby-on-rails - 使用 Sublime Text 3 突出显示 HTML 背景语法中的 ERB? - 2

    所以我在关注Railscast,我注意到在html.erb文件中,ruby代码有一个微弱的背景高亮效果,以区别于其他代码HTML文档。我知道Ryan使用TextMate。我正在使用SublimeText3。我怎样才能达到同样的效果?谢谢! 最佳答案 为SublimeText安装ERB包。假设您安装了SublimeText包管理器*,只需点击cmd+shift+P即可获得命令菜单,然后键入installpackage并选择PackageControl:InstallPackage获取包管理器菜单。在该菜单中,键入ERB并在看到包时选择

  8. ruby-on-rails - Ruby url 到 html 链接转换 - 2

    我正在使用Rails构建一个简单的聊天应用程序。当用户输入url时,我希望将其输出为html链接(即“url”)。我想知道在Ruby中是否有任何库或众所周知的方法可以做到这一点。如果没有,我有一些不错的正则表达式示例代码可以使用... 最佳答案 查看auto_linkRails提供的辅助方法。这会将所有URL和电子邮件地址变成可点击的链接(htmlanchor标记)。这是文档中的代码示例。auto_link("Gotohttp://www.rubyonrails.organdsayhellotodavid@loudthinking.

  9. ruby-on-rails - Ruby on Rails - 为文本区域和图片生成列 - 2

    我是Rails的新手,所以请原谅简单的问题。我正在为一家公司创建一个网站。那家公司想在网站上展示它的客户。我想让客户自己管理这个。我正在为“客户”生成一个表格,我想要的三列是:公司名称、公司描述和Logo。对于名称,我使用的是name:string但不确定如何在脚本/生成脚手架终端命令中最好地创建描述列(因为我打算将其设置为文本区域)和图片。我怀疑描述(我想成为一个文本区域)应该仍然是描述:字符串,然后以实际形式进行调整。不确定如何处理图片字段。那么……说来话长:我在脚手架命令中输入什么来生成描述和图片列? 最佳答案 对于“文本”数

  10. ruby-on-rails - 如何生成传递一些自定义参数的 `link_to` URL? - 2

    我正在使用RubyonRails3.0.9,我想生成一个传递一些自定义参数的link_toURL。也就是说,有一个articles_path(www.my_web_site_name.com/articles)我想生成如下内容:link_to'Samplelinktitle',...#HereIshouldimplementthecode#=>'http://www.my_web_site_name.com/articles?param1=value1¶m2=value2&...我如何编写link_to语句“alàRubyonRailsWay”以实现该目的?如果我想通过传递一些

随机推荐