公司需要设计一个稳定性测试,就是一直持续的跑不同的用例,直到人为停止,用例基本完成,基本框架思路就是随机选择一个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报告的更多相关文章

  1. 使用强大的 Mockito 测试框架来测试你的代码

    原文链接 : Unit tests with Mockito - Tutorial 译文出自 : 掘金翻译计划 译者 : edvardhua 校对者: hackerkevin, futureshine ...

  2. web测试中的测试点和测试方法总结

    测试是一种思维,包括情感思维和智力思维,情感思维主要体现在一句俗语:思想决定行动上(要怀疑一切),智力思维主要体现在测试用例的设计上.具有了这样的思想,就会找出更多的bug.   一.输入框 1.字符 ...

  3. IOS(SystemConfiguration)框架中关于测试连接网络状态相关方法

    1. 在SystemConfiguration.famework中提供和联网相关的function, 可用来检查网络连接状态. 2. SC(SystemConfiguration)框架中关于测试连接网 ...

  4. iOS开发中的测试框架

    转载作者:@crespoxiao 我们为什么要用测试框架呢?当然对项目开发有帮助了,但是业内现状是经常赶进度,所以TDD还是算了吧,BDD就测测数据存取和重要环节,这很重要,一次性跑完测试单元检查接口 ...

  5. iOS开发中的测试框架 (转载)

      作者:CrespoXiao授权 地址:http://www.jianshu.com/p/7e3f197504c1 我们为什么要用测试框架呢?当然对项目开发有帮助了,但是业内现状是经常赶进度,所以T ...

  6. python多线程在渗透测试中的应用

    难易程度:★★★ 阅读点:python;web安全; 文章作者:xiaoye 文章来源:i春秋 关键字:网络渗透技术 前言 python是门简单易学的语言,强大的第三方库让我们在编程中事半功倍,今天, ...

  7. 测试笔试单选题(持续更新ing)

    1.在GB/T17544中,软件包质量要求包括三部分,即产品描述要求._____.程 序和数据要求.( A ) A.用户文档要求 B.系统功能要求 C.设计要求说明 D.软件配置要求 2.软件的六大质 ...

  8. 专访|HPE测试中心总监徐盛:测试新思维-DevOps,持续测试,更敏捷,更快速

    2016年7月22日,「HPE&msup软件技术开放日」将在上海浦东新区,张江高科技园区纳贤路799号科荣大厦小楼2楼举办,msup携手HPE揭秘全球测试中心背后的12条技术实践. 徐盛:HP ...

  9. 详述MySQL服务在渗透测试中的利用

    本文作者:i春秋签约作家——Binghe 致力于书写ichunqiu社区历史上最长篇最细致最真实的技术复现文章. 文章目录: MySQL之UDF提权 MySQL之MOF提权 MySQL之常规写启动项提 ...

随机推荐

  1. 关系型数据库 和 非关系型数据对比 以及 MySQL与Oracle对比

    一.关系型数据库 关系型数据库,是指采用了关系模型来组织数据的数据库.    关系模型1970年提出的,关系模型的概念得到了充分的发展并逐渐成为主流数据库结构的主流模型.    简单来说,关系模型指的 ...

  2. linux下主流的三种远程技术

    远程登录操作对于租用服务器的用户来说都不陌生.特别是租用国外服务器的用户来说,更是家常便饭.通过远程登录操作,即使我们人在深圳,也能无差别的操作远在美国的服务器.而对于linux系统下的服务器,目前主 ...

  3. python,如何获取字符串中的子字符串,部分字符串

    说明: 比如有一个字符串,python,如何就获取前3位,或者后2位.在此记录下. 操作过程: 1.通过分割符的方式,下标的方式,获取字符串中的子串 >>> text = 'pyth ...

  4. 用plsql 导入导出oracle表结构数据

    一.导出 (1)导出数据 进入pl/sql,"工具"---->"Export Tables...",然后在弹出的对话框中选择要导出的表,最后点击" ...

  5. ios学习之UIWebView网页视图调整

    //先来一个可行的小Demo程序:结合searchBar的google搜索 #import <UIKit/UIKit.h> @interface ViewController : UIVi ...

  6. 随笔 -- NIO -- 相关 -- 系统概述

    .打开Selector .打开ServerSocketChannel .获取与此Channel关联的ServerSocket并绑定地址 .设置Channel为非阻塞 .将Channel注册到Selec ...

  7. 8 -- 深入使用Spring -- 3...1 Resource实现类UrlResource

    8.3.1 Resource 实现类------UrlResource : 访问网络资源的实现类 1.访问网络资源 访问网络资源通过UrlResource 类实现,UrlResource是java.n ...

  8. PHP开发中,让var_dump调试函数输出更美观 ^_^#

    前提:php必须安装Xdebug模块. 用var_dump打印输出时,输出的内容没有被格式化.如下图: 通常使用var_dump打印的内容是被格式化后输出的,如下图: 造成没有格式化输出的原因是因为p ...

  9. WSGI简介

    当我们实现一个Web应用(application)的时候,通常不会考虑如何接受HTTP请求.解析HTTP请求.发送HTTP响应等等,我们只关心处理逻辑,而不用去关心HTTP规范的细节. 之所以有这层透 ...

  10. 解决select2在modal中无法输入的问题

    解决办法: 在js里加一句 $.fn.modal.Constructor.prototype.enforceFocus = function(){};