在稳定性测试中,将测试结果持续填加进入html报告
公司需要设计一个稳定性测试,就是一直持续的跑不同的用例,直到人为停止,用例基本完成,基本框架思路就是随机选择一个testcase,跑完后输出结果。但存在一个问题,现在的unittest或nose测试报告都是测完所有case后再输出html报告,再次运行,又生成新的,没法再原来的报告中再填加结果。
就这样问题,基本解决思路就是直接写个生成html报告的模块,然后再次每次结果加入。正好最近在看tempest的东西,里面有个这样的模块,那就不重复造轮子了,直接拿过来用吧。
先看看生成html_log.py文件
- import shutil
- try:
- import xml.etree.cElementTree as ET
- except Exception:
- import xml.etree.ElementTree as ET
- TYPE_OK = 0
- TYPE_ERROR = -1
- TYPE_FAIL = -2
- TYPE_SKIP = -3
- class InfoParser(object):
- def __init__(self, file_path, info):
- self.file_path = file_path
- self.info = info
- def get_state(self):
- if self.info.find('... ok') != -1:
- return TYPE_OK
- elif self.info.find('... ERROR') != -1:
- return TYPE_ERROR
- elif self.info.find('... FAIL') != -1:
- return TYPE_FAIL
- elif self.info.find('... SKIP') != -1:
- return TYPE_SKIP
- def get_detail(self):
- if self.get_state() == 0:
- return ''
- else:
- offset = self.info.find('Traceback')
- if offset != -1:
- temp = self.info[offset:]
- return temp
- else:
- return ''
- def get_class_name(self):
- temp = self.get_testcase_name()
- offset = temp.rfind('.')
- if offset != -1:
- temp = temp[0: offset]
- return temp
- else:
- return ''
- def get_testcase_name(self):
- offset = self.info.find(' ...')
- if offset != -1:
- temp = self.info[0: offset]
- return temp
- return ''
- def create_new_overview_node(self, root, state, class_name):
- new_node = ET.Element('tr')
- root.insert(len(root.getchildren()) - 1, new_node)
- # testcase name
- sub_node = ET.SubElement(new_node, 'td')
- sub_node.text = class_name
- for x in range(5):
- sub_node = ET.SubElement(new_node, 'td')
- sub_node.text = '0'
- return new_node
- def add_overview_node_detail(self, item, state):
- item[5].text = str(int(item[5].text) + 1)
- if state == TYPE_FAIL:
- item[1].text = str(int(item[1].text) + 1)
- item[1].set('class', 'failed')
- elif state == TYPE_ERROR:
- item[2].text = str(int(item[2].text) + 1)
- item[2].set('class', 'failed')
- elif state == TYPE_SKIP:
- item[3].text = str(int(item[3].text) + 1)
- elif state == TYPE_OK:
- item[4].text = str(int(item[4].text) + 1)
- def add_to_overview(self, root, state, class_name):
- iter = root.getchildren()
- for item in iter:
- if item[0].text == class_name:
- self.add_overview_node_detail(item, state)
- # handle total
- total_item = root[len(root.getchildren()) - 1]
- self.add_overview_node_detail(total_item, state)
- return
- new_item = self.create_new_overview_node(root, state, class_name)
- self.add_overview_node_detail(new_item, state)
- # handle total
- total_item = root[len(root.getchildren()) - 1]
- self.add_overview_node_detail(total_item, state)
- def add_to_failure(self, root):
- new_item = ET.SubElement(root, 'section')
- # name
- sub_item = ET.SubElement(new_item, 'h3')
- sub_item.text = self.get_testcase_name()
- # details
- sub_item = ET.SubElement(new_item, 'div')
- sub_item.set('class', 'test-details')
- detail_sub_item = ET.SubElement(sub_item, 'h4')
- detail_sub_item.text = 'Detail'
- detail_sub_item = ET.SubElement(sub_item, 'pre')
- detail_sub_item.text = self.get_detail()
- def add_to_all_tests(self, root, state):
- new_item = ET.SubElement(root, 'li')
- sub_item = ET.SubElement(new_item, 'a')
- sub_item.text = self.get_testcase_name()
- if state == TYPE_FAIL or state == TYPE_ERROR:
- sub_item.set('class', 'failed')
- else:
- sub_item.set('class', 'success')
- def write_log(self):
- ret = self.get_state()
- tree = ET.parse(self.file_path)
- root = tree.getroot()
- # add overview
- self.add_to_overview(
- root.find('body').find('overview').find('section').find('table'),
- ret, self.get_class_name())
- # add fail view
- if ret == TYPE_FAIL or ret == TYPE_ERROR:
- self.add_to_failure(
- root.find('body').find('failure_details').
- find('section').find('div'))
- # add all tests
- self.add_to_all_tests(
- root.find('body').find('all_tests').find('section').find('ul'),
- ret)
- tree.write(self.file_path)
- def create_log_from_file(path, souce):
- shutil.copyfile(souce, path)
- def add_log(path, info):
- info_parser = InfoParser(path, info)
- info_parser.write_log()
- def format_testrunner_info(test, info, state):
- result = ''
- # handle name
- name = str(test)
- offset_b = name.find('(')
- offset_e = name.find(')')
- testcase_name = 'no name'
- if offset_b != -1 and offset_e != -1:
- testcase_name = name[offset_b + 1: offset_e]
- offset_e = name.find(' (')
- if offset_e != -1:
- testcase_name += '.'
- testcase_name += name[0: offset_e]
- result = testcase_name
- if state == TYPE_OK:
- result += ' ... ok\n\n'
- elif state == TYPE_ERROR:
- result += ' ... ERROR\n\n'
- elif state == TYPE_FAIL:
- result += ' ... FAIL\n\n'
- elif state == TYPE_SKIP:
- result += ' ... SKIP\n\n'
- result += info
- return result
- def add_testrunner_log(path, result, test_name):
- # success
- if result.wasSuccessful():
- info = format_testrunner_info(test_name, 'Ran 1 test', TYPE_OK)
- #info = format_testrunner_info(name,'Ran 1 test',TYPE_OK)
- add_log(path, info)
- # fail
- for test, err in result.failures:
- info = format_testrunner_info(test, err, TYPE_FAIL)
- add_log(path, info)
- # error
- for name, err in result.errors:
- info = format_testrunner_info(name, err, TYPE_ERROR)
- add_log(path, info)
- # skip
- for test, reason in result.skipped:
- info = format_testrunner_info(test, reason, TYPE_SKIP)
- add_log(path, info)
使用非常简单,使用对应的空报告模板,使生成的结果调用add_testrunner_log写入空模板中,最后就可以持续生成报告了
空模板见下面的html代码,copy下来后存成html文件即可使用
- <!DOCTYPE html>
- <html>
- <head>
- <title>Unit Test Report</title>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
- <style>
- body {
- font-family: Calibri, "Trebuchet MS", sans-serif;
- }
- * {
- word-break: break-all;
- }
- table, td, th, .dataid {
- border: 1px solid #aaa;
- border-collapse: collapse;
- background: #fff;
- }
- section {
- background: rgba(0, 0, 0, 0.05);
- margin: 2ex;
- padding: 1ex;
- border: 1px solid #999;
- border-radius: 5px;
- }
- h1 {
- font-size: 130%;
- }
- h2 {
- font-size: 120%;
- }
- h3 {
- font-size: 100%;
- }
- h4 {
- font-size: 85%;
- }
- h1, h2, h3, h4, a[href] {
- cursor: pointer;
- color: #0074d9;
- text-decoration: none;
- }
- h3 strong, a.failed {
- color: #ff4136;
- }
- .failed {
- color: #ff4136;
- }
- a.success {
- color: #3d9970;
- }
- pre {
- font-family: 'Consolas', 'Deja Vu Sans Mono',
- 'Bitstream Vera Sans Mono', 'Monaco',
- 'Courier New', monospace;
- }
- .test-details,
- .traceback {
- display: none;
- }
- section:target .test-details {
- display: block;
- }
- </style>
- </head>
- <body>
- <overview>
- <h1>Overview</h1>
- <section>
- <table>
- <tr>
- <th>Class</th>
- <th class="failed">Fail</th>
- <th class="failed">Error</th>
- <th>Skip</th>
- <th>Success</th>
- <th>Total</th>
- </tr>
- <tr>
- <td><strong>Total</strong></td>
- <td>0</td>
- <td>0</td>
- <td>0</td>
- <td>0</td>
- <td>0</td>
- </tr>
- </table>
- </section>
- </overview>
- <failure_details>
- <h1>Failure details</h1>
- <section>
- <h2>Failure details</h2>
- <div>
- </div>
- </section>
- </failure_details>
- <all_tests>
- <h1>All tests</h1>
- <section>
- <h2>all tests</h2>
- <ul>
- </ul>
- </section>
- </all_tests>
- </body>
- <script>
- Array.prototype.forEach.call(document.querySelectorAll('h1, h2, h3, h4'), function(el) {
- el.addEventListener('click', function() {
- el.nextElementSibling.style.display = document.defaultView.getComputedStyle(el.nextElementSibling).display == 'none' ? 'block' : 'none';
- })
- })
- </script>
使用unittest写个示范代码如下:
- import unittest
- import time
- import sys
- import html_log
- import os
- import re
- import random
- class test(unittest.TestCase):
- def setUp(self):
- pass
- def test_0001(self):
- assert 1==1
- def test_0002(self):
- assert 2==2
- if __name__=='__main__':
- suite=unittest.TestLoader().loadTestsFromTestCase(test)
- testcases=list()
- listcasedir='.'
- testunit=unittest.TestSuite()
- #选择case
- for test_case in suite:
- print test_case
- f=re.match("(test_.*) \(__main__.test\)",str(test_case))
- tt=f.group(1)
- testcases.append(test_case)
- test = random.choice(testcases)
- mySuite = unittest.TestSuite()
- mySuite.addTest(test)
- result = unittest.TextTestRunner().run(mySuite)
- #这里xx.html就是对应的空模板
if not os.path.exists('test_aa.html'):- html_log.create_log_from_file('test_aa.html', 'xx.html')
- #将结果持续加入到对应的html报告中
- print test
- html_log.add_testrunner_log('test_aa.html', result, test)
结果如下,测试一直在进行,结果就一直会持续输入
在稳定性测试中,将测试结果持续填加进入html报告的更多相关文章
- 使用强大的 Mockito 测试框架来测试你的代码
原文链接 : Unit tests with Mockito - Tutorial 译文出自 : 掘金翻译计划 译者 : edvardhua 校对者: hackerkevin, futureshine ...
- web测试中的测试点和测试方法总结
测试是一种思维,包括情感思维和智力思维,情感思维主要体现在一句俗语:思想决定行动上(要怀疑一切),智力思维主要体现在测试用例的设计上.具有了这样的思想,就会找出更多的bug. 一.输入框 1.字符 ...
- IOS(SystemConfiguration)框架中关于测试连接网络状态相关方法
1. 在SystemConfiguration.famework中提供和联网相关的function, 可用来检查网络连接状态. 2. SC(SystemConfiguration)框架中关于测试连接网 ...
- iOS开发中的测试框架
转载作者:@crespoxiao 我们为什么要用测试框架呢?当然对项目开发有帮助了,但是业内现状是经常赶进度,所以TDD还是算了吧,BDD就测测数据存取和重要环节,这很重要,一次性跑完测试单元检查接口 ...
- iOS开发中的测试框架 (转载)
作者:CrespoXiao授权 地址:http://www.jianshu.com/p/7e3f197504c1 我们为什么要用测试框架呢?当然对项目开发有帮助了,但是业内现状是经常赶进度,所以T ...
- python多线程在渗透测试中的应用
难易程度:★★★ 阅读点:python;web安全; 文章作者:xiaoye 文章来源:i春秋 关键字:网络渗透技术 前言 python是门简单易学的语言,强大的第三方库让我们在编程中事半功倍,今天, ...
- 测试笔试单选题(持续更新ing)
1.在GB/T17544中,软件包质量要求包括三部分,即产品描述要求._____.程 序和数据要求.( A ) A.用户文档要求 B.系统功能要求 C.设计要求说明 D.软件配置要求 2.软件的六大质 ...
- 专访|HPE测试中心总监徐盛:测试新思维-DevOps,持续测试,更敏捷,更快速
2016年7月22日,「HPE&msup软件技术开放日」将在上海浦东新区,张江高科技园区纳贤路799号科荣大厦小楼2楼举办,msup携手HPE揭秘全球测试中心背后的12条技术实践. 徐盛:HP ...
- 详述MySQL服务在渗透测试中的利用
本文作者:i春秋签约作家——Binghe 致力于书写ichunqiu社区历史上最长篇最细致最真实的技术复现文章. 文章目录: MySQL之UDF提权 MySQL之MOF提权 MySQL之常规写启动项提 ...
随机推荐
- 用好这6个APP,学英语SO EASY!
http://www.jianshu.com/p/30a27af18340
- Java基础之深入理解Class对象与反射机制
深入理解Class对象 RRIT及Class对象的概念 RRIT(Run-Time Type Identification)运行时类型识别.在<Thinking in Java>一书第十四 ...
- 快速排查SQL服务器阻塞语句
SELECT*FROM sys.sysprocesses and blocked> --可以查看阻塞 SELECT SPID=p.spid, DBName =convert(CHAR(),d.n ...
- 阿里云提出的漏洞(Phpcms V9某处逻辑问题导致getshell漏洞解决方法)的问题
最近从阿里云云盾检测流出来的,相比使用阿里云服务器的朋友已经收到漏洞提醒:Phpcms V9某处逻辑问题导致getshell漏洞解决方法,这个漏洞怎么办呢?CMSYOU在这里找到针对性解决办法分享给大 ...
- 用highcharts展现你的数据
摘要: 前面已经分享过图表插件,今天在来将下如何使用highcharts来绘制图表.highcharts支持在线定制,你可以选择你所需要的模块,然后点击build就会生成一个js文件链接,右键保存到本 ...
- C# base和this的用法
/** this关键字* this关键字引用类的当前实例* 注意:静态成员方法中不能使用this关键字,this关键字只能在实例构造函数.实例方法或实例访问器中使用*/ /** base关键字* ba ...
- CentOS 6.3下搭建Web服务器
准备前的工作: 1.修改selinux配置文件(/etc/sysconfig/selinux) 关闭防火墙 (1)把SELINUX=enforcing注释掉 (2)并添加SELINUX=disable ...
- win7+ oracle +php环境的搭建
http://blog.csdn.net/chchmlml/article/details/6887326 先下载个wmpp1.7.5(之前在xp上也是这个,所以就继续),安装,一切顺利,打开phpi ...
- ios开发之--仿(微信)自定义表情键盘
先附上demo:https://github.com/hgl753951/CusEmoji.git 效果图如下:
- iOS App Extensions
一.扩展概述 扩展(Extension)是iOS 8中引入的一个非常重要的新特性.扩展让app之间的数据交互成为可能.用户可以在app中使用其他应用提供的功能,而无需离开当前的应用. 在iOS 8系统 ...