Unitest自动化测试基于HTMLTestRunner报告案例

报告效果如下:

Unitest自动化测试基于HTMLTestRunner报告案例

HTMLTestRunner脚本代码如下:

#coding=utf-8

# URL: http://tungwaiyip.info/software/HTMLTestRunner.html

__author__ = "Wai Yip Tung,  Findyou"
__version__ = "0.8.2.1"

"""
Version 0.8.2.1 -Findyou
* 支持中文,汉化
* 调整样式,美化(需要连入网络,使用的百度的Bootstrap.js)
* 增加 通过分类显示、测试人员、通过率的展示
* 优化“详细”与“收起”状态的变换
* 增加返回顶部的锚点
"""

import datetime
import io
import sys
import time
import unittest
from xml.sax import saxutils
import sys
#reload(sys)
#sys.setdefaultencoding('utf-8')

class OutputRedirector(object):
    def __init__(self, fp):
        self.fp = fp

    def write(self, s):
        self.fp.write(s)

    def writelines(self, lines):
        self.fp.writelines(lines)

    def flush(self):
        self.fp.flush()

stdout_redirector = OutputRedirector(sys.stdout)
stderr_redirector = OutputRedirector(sys.stderr)

class Template_mixin(object):
    """
    Overall structure of an HTML report

    HTML
    +------------------------+
    |                  |
    |                  |
    |                        |
    |   STYLESHEET           |
    |   +----------------+   |
    |   |                |   |
    |   +----------------+   |
    |                        |
    |                 |
    |                        |
    |                  |
    |                        |
    |   HEADING              |
    |   +----------------+   |
    |   |                |   |
    |   +----------------+   |
    |                        |
    |   REPORT               |
    |   +----------------+   |
    |   |                |   |
    |   +----------------+   |
    |                        |
    |   ENDING               |
    |   +----------------+   |
    |   |                |   |
    |   +----------------+   |
    |                        |
    |                 |
    |                 |
    +------------------------+
    """

    STATUS = {
    0: '通过',
    1: '失败',
    2: '错误',
    }

    # 默认测试标题
    DEFAULT_TITLE = '接口自动化测试报告'
    DEFAULT_DESCRIPTION = ''
    # 默认测试人员
    DEFAULT_TESTER = 'Agoly'

    # ------------------------------------------------------------------------
    # HTML Template

    HTML_TMPL = r"""




    %(title)s
    
    
    
    
    
    %(stylesheet)s



%(heading)s
%(report)s
%(ending)s



"""
    # variables: (title, generator, stylesheet, heading, report, ending)

    STYLESHEET_TMPL = """

"""

    # ------------------------------------------------------------------------
    # Heading
    #
# 

面板标题

HEADING_TMPL = """

%(title)s

%(parameters)s
%(description)s

""" # variables: (title, parameters, description) HEADING_ATTRIBUTE_TMPL = """

%(name)s : %(value)s

""" # variables: (name, value) # ------------------------------------------------------------------------ # Report # # 汉化,加美化效果 --Findyou REPORT_TMPL = """

通过率【%(passrate)s】 失败【%(fail)s】 成功【%(Pass)s】 所有【%(count)s】

%(test_list)s
用例集/测试用例 总计 通过 失败 错误 详细
总计 %(count)s %(Pass)s %(fail)s %(error)s 通过率:%(passrate)s
""" # variables: (test_list, count, Pass, fail, error ,passrate) REPORT_CLASS_TMPL = r""" %(desc)s %(count)s %(Pass)s %(fail)s %(error)s 详细 """ # variables: (style, desc, count, Pass, fail, error, cid) #失败 的样式,去掉原来JS效果,美化展示效果 -Findyou REPORT_TEST_WITH_OUTPUT_TMPL = r"""
%(desc)s
    %(script)s
    

""" # variables: (tid, Class, style, desc, status)

# 通过 的样式,加标签效果 -Findyou
#REPORT_TEST_NO_OUTPUT_TMPL = r"""
#
#

%(desc)s


#

%(status)s


#

# 通过 的样式,加标签效果 -Findyou
REPORT_TEST_NO_OUTPUT_TMPL=r"""

%(desc)s


    %(script)s
    

""" # variables: (tid, Class, style, desc, status)

REPORT_TEST_OUTPUT_TMPL
= r"""
%(output)s
""" # variables: (id, output)

# ------------------------------------------------------------------------
# ENDING
#
# 增加返回顶部按钮 --Findyou
ENDING_TMPL = """"""

# -------------------- The end of the Template class -------------------

TestResult = unittest.TestResult

class _TestResult(TestResult):
# note: _TestResult is a pure representation of results.
# It lacks the output and reporting ability compares to unittest._TextTestResult.

def __init__(self, verbosity=1):
TestResult.
__init__(self)
self.stdout0
= None
self.stderr0
= None
self.success_count
= 0
self.failure_count
= 0
self.error_count
= 0
self.verbosity
= verbosity

# result is a list of result in 4 tuple
# (
# result code (0: success; 1: fail; 2: error),
# TestCase object,
# Test output (byte string),
# stack trace,
# )
self.result = []
#增加一个测试通过率 --Findyou
self.passrate=float(0)

def startTest(self, test):
TestResult.startTest(self, test)
# just one buffer for both stdout and stderr
self.outputBuffer = io.StringIO()
stdout_redirector.fp
= self.outputBuffer
stderr_redirector.fp
= self.outputBuffer
self.stdout0
= sys.stdout
self.stderr0
= sys.stderr
sys.stdout
= stdout_redirector
sys.stderr
= stderr_redirector

def complete_output(self):
"""
Disconnect output redirection and return buffer.

Safe to call multiple times.

"""
if self.stdout0:
sys.stdout
= self.stdout0
sys.stderr
= self.stderr0
self.stdout0
= None
self.stderr0
= None
return self.outputBuffer.getvalue()

def stopTest(self, test):
# Usually one of addSuccess, addError or addFailure would have been called.
# But there are some path in unittest that would bypass this.
# We must disconnect stdout in stopTest(), which is guaranteed to be called.
self.complete_output()

def addSuccess(self, test):
self.success_count
+= 1
TestResult.addSuccess(self, test)
output
= self.complete_output()
self.result.append((0, test, output,
''))
if self.verbosity > 1:
sys.stderr.write(
'ok ')
sys.stderr.write(str(test))
sys.stderr.write(
'\n')
else:
sys.stderr.write(
'.')

def addError(self, test, err):
self.error_count
+= 1
TestResult.addError(self, test, err)
_, _exc_str
= self.errors[-1]
output
= self.complete_output()
self.result.append((
2, test, output, _exc_str))
if self.verbosity > 1:
sys.stderr.write(
'E ')
sys.stderr.write(str(test))
sys.stderr.write(
'\n')
else:
sys.stderr.write(
'E')

def addFailure(self, test, err):
self.failure_count
+= 1
TestResult.addFailure(self, test, err)
_, _exc_str
= self.failures[-1]
output
= self.complete_output()
self.result.append((
1, test, output, _exc_str))
if self.verbosity > 1:
sys.stderr.write(
'F ')
sys.stderr.write(str(test))
sys.stderr.write(
'\n')
else:
sys.stderr.write(
'F')

class HTMLTestRunner(Template_mixin):
"""
"""
def __init__(self, stream=sys.stdout, verbosity=1,title=None,description=None,tester=None):
self.stream
= stream
self.verbosity
= verbosity
if title is None:
self.title
= self.DEFAULT_TITLE
else:
self.title
= title
if description is None:
self.description
= self.DEFAULT_DESCRIPTION
else:
self.description
= description
if tester is None:
self.tester
= self.DEFAULT_TESTER
else:
self.tester
= tester

self.startTime = datetime.datetime.now()

def run(self, test):
"Run the given test case or test suite."
result
= _TestResult(self.verbosity)
test(result)
self.stopTime
= datetime.datetime.now()
self.generateReport(test, result)
#print(sys.stderr, '\nTime Elapsed: %s' % (self.stopTime-self.startTime))
print('\nTime Elapsed: %s' % (self.stopTime - self.startTime), file=sys.stderr)
return result

def sortResult(self, result_list):
# unittest does not seems to run in any particular order.
# Here at least we want to group them together by class.
rmap = {}
classes
= []
for n,t,o,e in result_list:
cls
= t.__class__
if not cls in rmap:
rmap[cls]
= []
classes.append(cls)
rmap[cls].append((n,t,o,e))
r
= [(cls, rmap[cls]) for cls in classes]
return r

#替换测试结果status为通过率 --Findyou
def getReportAttributes(self, result):
"""
Return report attributes as a list of (name, value).

Override this to add custom attributes.

"""
startTime
= str(self.startTime)[:19]
duration
= str(self.stopTime - self.startTime)[:10]
status
= []
status.append(
'【总共:%s】' % (result.success_count + result.failure_count + result.error_count))
if result.success_count:
status.append(
'【通过:%s】' % result.success_count)
if result.failure_count:
status.append(
'【失败:%s】' % result.failure_count)
if result.error_count:
status.append(
'【错误:%s】' % result.error_count)
if status:
status
= ' '.join(status)
try:
self.passrate
= str("%.2f%%" % (float(result.success_count) / float(result.success_count + result.failure_count + result.error_count) * 100))
except ZeroDivisionError:
self.passrate
= 0
else:
status
= 'none'
print(status)
return [
(u
'测试人员', self.tester),
(u
'开始时间',startTime),
(u
'合计耗时',duration),
(
'测试结果',status + "【通过率= "+self.passrate+''),
]

def generateReport(self, test, result):
report_attrs
= self.getReportAttributes(result)
generator
= 'HTMLTestRunner %s' % __version__
stylesheet
= self._generate_stylesheet()
heading
= self._generate_heading(report_attrs)
report
= self._generate_report(result)
ending
= self._generate_ending()
output
= self.HTML_TMPL % dict(
title
= saxutils.escape(self.title),
generator
= generator,
stylesheet
= stylesheet,
heading
= heading,
report
= report,
ending
= ending,
)
self.stream.write(output.encode(
'utf8'))

def _generate_stylesheet(self):
return self.STYLESHEET_TMPL

#增加Tester显示 -Findyou
def _generate_heading(self, report_attrs):
a_lines
= []
for name, value in report_attrs:
line
= self.HEADING_ATTRIBUTE_TMPL % dict(
name
= saxutils.escape(name),
value
= saxutils.escape(value),
)
a_lines.append(line)
heading
= self.HEADING_TMPL % dict(
title
= saxutils.escape(self.title),
parameters
= ''.join(a_lines),
description
= saxutils.escape(self.description),
tester
= saxutils.escape(self.tester),
)
return heading

#生成报告 --Findyou添加注释
def _generate_report(self, result):
rows
= []
sortedResult
= self.sortResult(result.result)
for cid, (cls, cls_results) in enumerate(sortedResult):
# subtotal for a class
np = nf = ne = 0
for n,t,o,e in cls_results:
if n == 0: np += 1
elif n == 1: nf += 1
else: ne += 1

# format class description
if cls.__module__ == "__main__":
name
= cls.__name__
else:
name
= "%s.%s" % (cls.__module__, cls.__name__)
doc
= cls.__doc__ and cls.__doc__.split("\n")[0] or ""
desc
= doc and '%s: %s' % (name, doc) or name

row = self.REPORT_CLASS_TMPL % dict(
style
= ne > 0 and 'errorClass' or nf > 0 and 'failClass' or 'passClass',
desc
= desc,
count
= np+nf+ne,
Pass
= np,
fail
= nf,
error
= ne,
cid
= 'c%s' % (cid+1),
)
rows.append(row)

for tid, (n,t,o,e) in enumerate(cls_results):
self._generate_report_test(rows, cid, tid, n, t, o, e)

report = self.REPORT_TMPL % dict(
test_list
= ''.join(rows),
count
= str(result.success_count+result.failure_count+result.error_count),
Pass
= str(result.success_count),
fail
= str(result.failure_count),
error
= str(result.error_count),
passrate
=self.passrate,
)
return report

def _generate_report_test(self, rows, cid, tid, n, t, o, e):
# e.g. 'pt1.1', 'ft1.1', etc
has_output = bool(o or e)
# ID修改点为下划线,支持Bootstrap折叠展开特效 - Findyou
tid = (n == 0 and 'p' or 'f') + 't%s_%s' % (cid+1,tid+1)
name
= t.id().split('.')[-1]
doc
= t.shortDescription() or ""
desc
= doc and ('%s: %s' % (name, doc)) or name
tmpl
= has_output and self.REPORT_TEST_WITH_OUTPUT_TMPL or self.REPORT_TEST_NO_OUTPUT_TMPL

# utf-8 支持中文 - Findyou
# o and e should be byte string because they are collected from stdout and stderr?
if isinstance(o, str):
# TODO: some problem with 'string_escape': it escape \n and mess up formating
# uo = unicode(o.encode('string_escape'))
# uo = o.decode('latin-1')
uo = o
else:
uo
= o
if isinstance(e, str):
# TODO: some problem with 'string_escape': it escape \n and mess up formating
# ue = unicode(e.encode('string_escape'))
# ue = e.decode('latin-1')
ue = e
else:
ue
= e

script = self.REPORT_TEST_OUTPUT_TMPL % dict(
# id = tid,
id = '',
output
= saxutils.escape(uo+ue),
)

row = tmpl % dict(
tid
= tid,
Class
= (n == 0 and 'hiddenRow' or 'none'),
style
= n == 2 and 'errorCase' or (n == 1 and 'failCase' or 'passCase'),
desc
= desc,
script
= script,
status
= self.STATUS[n],
)
rows.append(row)
if not has_output:
return

def _generate_ending(self):
return self.ENDING_TMPL

##############################################################################
#
Facilities for running tests from the command line
#
#############################################################################

# Note: Reuse unittest.TestProgram to launch test. In the future we may
#
build our own launcher to support more specific command line
#
parameters like test title, CSS, etc.
class TestProgram(unittest.TestProgram):
"""
A variation of the unittest.TestProgram. Please refer to the base
class for command line parameters.

"""
def runTests(self):
# Pick HTMLTestRunner as the default test runner.
# base class's testRunner parameter is not useful because it means
# we have to instantiate HTMLTestRunner before we know self.verbosity.
if self.testRunner is None:
self.testRunner
= HTMLTestRunner(verbosity=self.verbosity)
unittest.TestProgram.runTests(self)

main = TestProgram

##############################################################################
#
Executing this module from the command line
#
#############################################################################

if __name__ == "__main__":
main(module
=None)

模板2:

Unitest自动化测试基于HTMLTestRunner报告案例
#coding=utf-8

# URL: http://tungwaiyip.info/software/HTMLTestRunner.html

__author__ = "Wai Yip Tung,  Findyou"
__version__ = "0.8.2.1"

"""
Version 0.8.2.1 -Findyou
* 支持中文,汉化
* 调整样式,美化(需要连入网络,使用的百度的Bootstrap.js)
* 增加 通过分类显示、测试人员、通过率的展示
* 优化“详细”与“收起”状态的变换
* 增加返回顶部的锚点
"""

import datetime
import io
import sys
import time
import unittest
from xml.sax import saxutils
import sys
#reload(sys)
#sys.setdefaultencoding('utf-8')

class OutputRedirector(object):
    def __init__(self, fp):
        self.fp = fp

    def write(self, s):
        self.fp.write(s)

    def writelines(self, lines):
        self.fp.writelines(lines)

    def flush(self):
        self.fp.flush()

stdout_redirector = OutputRedirector(sys.stdout)
stderr_redirector = OutputRedirector(sys.stderr)

class Template_mixin(object):
    """
    Overall structure of an HTML report

    HTML
    +------------------------+
    |                  |
    |                  |
    |                        |
    |   STYLESHEET           |
    |   +----------------+   |
    |   |                |   |
    |   +----------------+   |
    |                        |
    |                 |
    |                        |
    |                  |
    |                        |
    |   HEADING              |
    |   +----------------+   |
    |   |                |   |
    |   +----------------+   |
    |                        |
    |   REPORT               |
    |   +----------------+   |
    |   |                |   |
    |   +----------------+   |
    |                        |
    |   ENDING               |
    |   +----------------+   |
    |   |                |   |
    |   +----------------+   |
    |                        |
    |                 |
    |                 |
    +------------------------+
    """

    STATUS = {
    0: '通过',
    1: '失败',
    2: '错误',
    }

    # 默认测试标题
    DEFAULT_TITLE = '接口自动化测试报告'
    DEFAULT_DESCRIPTION = ''
    # 默认测试人员
    DEFAULT_TESTER = 'Agoly'

    # ------------------------------------------------------------------------
    # HTML Template

    HTML_TMPL = r"""




    %(title)s
    
    
    
    
    
    
    %(stylesheet)s



%(heading)s
%(report)s
%(ending)s
%(chart_script)s




"""  # variables: (title, generator, stylesheet, heading, report, ending, chart_script)

    ECHARTS_SCRIPT = """
    

"""
    # variables: (title, generator, stylesheet, heading, report, ending)

    STYLESHEET_TMPL = """

"""

    # ------------------------------------------------------------------------
    # Heading
    #
# 

面板标题

HEADING_TMPL = """

%(title)s

%(parameters)s
%(description)s

""" # variables: (title, parameters, description) HEADING_ATTRIBUTE_TMPL = """

%(name)s : %(value)s

""" # variables: (name, value) # ------------------------------------------------------------------------ # Report # # 汉化,加美化效果 --Findyou REPORT_TMPL = """

通过率【%(passrate)s】 失败【%(fail)s】 成功【%(Pass)s】 所有【%(count)s】

%(test_list)s
用例集/测试用例 总计 通过 失败 错误 详细
总计 %(count)s %(Pass)s %(fail)s %(error)s 通过率:%(passrate)s
""" # variables: (test_list, count, Pass, fail, error ,passrate) REPORT_CLASS_TMPL = r""" %(desc)s %(count)s %(Pass)s %(fail)s %(error)s 详细 """ # variables: (style, desc, count, Pass, fail, error, cid) #失败 的样式,去掉原来JS效果,美化展示效果 -Findyou REPORT_TEST_WITH_OUTPUT_TMPL = r"""
%(desc)s
    %(script)s
    

""" # variables: (tid, Class, style, desc, status)

# 通过 的样式,加标签效果 -Findyou
#REPORT_TEST_NO_OUTPUT_TMPL = r"""
#
#

%(desc)s


#

%(status)s


#

# 通过 的样式,加标签效果 -Findyou
REPORT_TEST_NO_OUTPUT_TMPL=r"""

%(desc)s


    %(script)s
    

""" # variables: (tid, Class, style, desc, status)

REPORT_TEST_OUTPUT_TMPL
= r"""
%(output)s
""" # variables: (id, output)

# ------------------------------------------------------------------------
# ENDING
#
# 增加返回顶部按钮 --Findyou
ENDING_TMPL = """"""

# -------------------- The end of the Template class -------------------

TestResult = unittest.TestResult

class _TestResult(TestResult):
# note: _TestResult is a pure representation of results.
# It lacks the output and reporting ability compares to unittest._TextTestResult.

def __init__(self, verbosity=1):
TestResult.
__init__(self)
self.stdout0
= None
self.stderr0
= None
self.success_count
= 0
self.failure_count
= 0
self.error_count
= 0
self.verbosity
= verbosity

# result is a list of result in 4 tuple
# (
# result code (0: success; 1: fail; 2: error),
# TestCase object,
# Test output (byte string),
# stack trace,
# )
self.result = []
#增加一个测试通过率 --Findyou
self.passrate=float(0)

def startTest(self, test):
TestResult.startTest(self, test)
# just one buffer for both stdout and stderr
self.outputBuffer = io.StringIO()
stdout_redirector.fp
= self.outputBuffer
stderr_redirector.fp
= self.outputBuffer
self.stdout0
= sys.stdout
self.stderr0
= sys.stderr
sys.stdout
= stdout_redirector
sys.stderr
= stderr_redirector

def complete_output(self):
"""
Disconnect output redirection and return buffer.

Safe to call multiple times.

"""
if self.stdout0:
sys.stdout
= self.stdout0
sys.stderr
= self.stderr0
self.stdout0
= None
self.stderr0
= None
return self.outputBuffer.getvalue()

def stopTest(self, test):
# Usually one of addSuccess, addError or addFailure would have been called.
# But there are some path in unittest that would bypass this.
# We must disconnect stdout in stopTest(), which is guaranteed to be called.
self.complete_output()

def addSuccess(self, test):
self.success_count
+= 1
TestResult.addSuccess(self, test)
output
= self.complete_output()
self.result.append((0, test, output,
''))
if self.verbosity > 1:
sys.stderr.write(
'ok ')
sys.stderr.write(str(test))
sys.stderr.write(
'\n')
else:
sys.stderr.write(
'.')

def addError(self, test, err):
self.error_count
+= 1
TestResult.addError(self, test, err)
_, _exc_str
= self.errors[-1]
output
= self.complete_output()
self.result.append((
2, test, output, _exc_str))
if self.verbosity > 1:
sys.stderr.write(
'E ')
sys.stderr.write(str(test))
sys.stderr.write(
'\n')
else:
sys.stderr.write(
'E')

def addFailure(self, test, err):
self.failure_count
+= 1
TestResult.addFailure(self, test, err)
_, _exc_str
= self.failures[-1]
output
= self.complete_output()
self.result.append((
1, test, output, _exc_str))
if self.verbosity > 1:
sys.stderr.write(
'F ')
sys.stderr.write(str(test))
sys.stderr.write(
'\n')
else:
sys.stderr.write(
'F')

class HTMLTestRunner(Template_mixin):
"""
"""
def __init__(self, stream=sys.stdout, verbosity=1,title=None,description=None,tester=None):
self.stream
= stream
self.verbosity
= verbosity
if title is None:
self.title
= self.DEFAULT_TITLE
else:
self.title
= title
if description is None:
self.description
= self.DEFAULT_DESCRIPTION
else:
self.description
= description
if tester is None:
self.tester
= self.DEFAULT_TESTER
else:
self.tester
= tester

self.startTime = datetime.datetime.now()

def run(self, test):
"Run the given test case or test suite."
result
= _TestResult(self.verbosity)
test(result)
self.stopTime
= datetime.datetime.now()
self.generateReport(test, result)
#print(sys.stderr, '\nTime Elapsed: %s' % (self.stopTime-self.startTime))
print('\nTime Elapsed: %s' % (self.stopTime - self.startTime), file=sys.stderr)
return result

def sortResult(self, result_list):
# unittest does not seems to run in any particular order.
# Here at least we want to group them together by class.
rmap = {}
classes
= []
for n,t,o,e in result_list:
cls
= t.__class__
if not cls in rmap:
rmap[cls]
= []
classes.append(cls)
rmap[cls].append((n,t,o,e))
r
= [(cls, rmap[cls]) for cls in classes]
return r

#替换测试结果status为通过率 --Findyou
def getReportAttributes(self, result):
"""
Return report attributes as a list of (name, value).

Override this to add custom attributes.

"""
startTime
= str(self.startTime)[:19]
duration
= str(self.stopTime - self.startTime)[:10]
status
= []
status.append(
'【总共:%s】' % (result.success_count + result.failure_count + result.error_count))
if result.success_count:
status.append(
'【通过:%s】' % result.success_count)
if result.failure_count:
status.append(
'【失败:%s】' % result.failure_count)
if result.error_count:
status.append(
'【错误:%s】' % result.error_count)
if status:
status
= ' '.join(status)
try:
self.passrate
= str("%.2f%%" % (float(result.success_count) / float(result.success_count + result.failure_count + result.error_count) * 100))
except ZeroDivisionError:
self.passrate
= 0
else:
status
= 'none'
print(status)
return [
(u
'测试人员', self.tester),
(u
'开始时间',startTime),
(u
'合计耗时',duration),
(
'测试结果',status + "【通过率= "+self.passrate+''),
]

def generateReport(self, test, result):
report_attrs
= self.getReportAttributes(result)
generator
= 'HTMLTestRunner %s' % __version__
stylesheet
= self._generate_stylesheet()
heading
= self._generate_heading(report_attrs)
report
= self._generate_report(result)
ending
= self._generate_ending()
chart
= self._generate_chart(result)
output
= self.HTML_TMPL % dict(
title
= saxutils.escape(self.title),
generator
= generator,
stylesheet
= stylesheet,
heading
= heading,
report
= report,
ending
= ending,
chart_script
=chart
)
self.stream.write(output.encode(
'utf8'))

def _generate_stylesheet(self):
return self.STYLESHEET_TMPL

#增加Tester显示 -Findyou
def _generate_heading(self, report_attrs):
a_lines
= []
for name, value in report_attrs:
line
= self.HEADING_ATTRIBUTE_TMPL % dict(
name
= saxutils.escape(name),
value
= saxutils.escape(value),
)
a_lines.append(line)
heading
= self.HEADING_TMPL % dict(
title
= saxutils.escape(self.title),
parameters
= ''.join(a_lines),
description
= saxutils.escape(self.description),
tester
= saxutils.escape(self.tester),
)
return heading

#生成报告 --Findyou添加注释
def _generate_report(self, result):
rows
= []
sortedResult
= self.sortResult(result.result)
for cid, (cls, cls_results) in enumerate(sortedResult):
# subtotal for a class
np = nf = ne = 0
for n,t,o,e in cls_results:
if n == 0: np += 1
elif n == 1: nf += 1
else: ne += 1

# format class description
if cls.__module__ == "__main__":
name
= cls.__name__
else:
name
= "%s.%s" % (cls.__module__, cls.__name__)
doc
= cls.__doc__ and cls.__doc__.split("\n")[0] or ""
desc
= doc and '%s: %s' % (name, doc) or name

row = self.REPORT_CLASS_TMPL % dict(
style
= ne > 0 and 'errorClass' or nf > 0 and 'failClass' or 'passClass',
desc
= desc,
count
= np+nf+ne,
Pass
= np,
fail
= nf,
error
= ne,
cid
= 'c%s' % (cid+1),
)
rows.append(row)

for tid, (n,t,o,e) in enumerate(cls_results):
self._generate_report_test(rows, cid, tid, n, t, o, e)

report = self.REPORT_TMPL % dict(
test_list
= ''.join(rows),
count
= str(result.success_count+result.failure_count+result.error_count),
Pass
= str(result.success_count),
fail
= str(result.failure_count),
error
= str(result.error_count),
passrate
=self.passrate,
)
return report

def _generate_chart(self, result):
chart
= self.ECHARTS_SCRIPT % dict(
Pass
=str(result.success_count),
fail
=str(result.failure_count),
error
=str(result.error_count),
)
return chart

def _generate_report_test(self, rows, cid, tid, n, t, o, e):
# e.g. 'pt1.1', 'ft1.1', etc
has_output = bool(o or e)
# ID修改点为下划线,支持Bootstrap折叠展开特效 - Findyou
tid = (n == 0 and 'p' or 'f') + 't%s_%s' % (cid+1,tid+1)
name
= t.id().split('.')[-1]
doc
= t.shortDescription() or ""
desc
= doc and ('%s: %s' % (name, doc)) or name
tmpl
= has_output and self.REPORT_TEST_WITH_OUTPUT_TMPL or self.REPORT_TEST_NO_OUTPUT_TMPL

# utf-8 支持中文 - Findyou
# o and e should be byte string because they are collected from stdout and stderr?
if isinstance(o, str):
# TODO: some problem with 'string_escape': it escape \n and mess up formating
# uo = unicode(o.encode('string_escape'))
# uo = o.decode('latin-1')
uo = o
else:
uo
= o
if isinstance(e, str):
# TODO: some problem with 'string_escape': it escape \n and mess up formating
# ue = unicode(e.encode('string_escape'))
# ue = e.decode('latin-1')
ue = e
else:
ue
= e

script = self.REPORT_TEST_OUTPUT_TMPL % dict(
# id = tid,
id = '',
output
= saxutils.escape(uo+ue),
)

row = tmpl % dict(
tid
= tid,
Class
= (n == 0 and 'hiddenRow' or 'none'),
style
= n == 2 and 'errorCase' or (n == 1 and 'failCase' or 'passCase'),
desc
= desc,
script
= script,
status
= self.STATUS[n],
)
rows.append(row)
if not has_output:
return

def _generate_ending(self):
return self.ENDING_TMPL

##############################################################################
#
Facilities for running tests from the command line
#
#############################################################################

# Note: Reuse unittest.TestProgram to launch test. In the future we may
#
build our own launcher to support more specific command line
#
parameters like test title, CSS, etc.
class TestProgram(unittest.TestProgram):
"""
A variation of the unittest.TestProgram. Please refer to the base
class for command line parameters.

"""
def runTests(self):
# Pick HTMLTestRunner as the default test runner.
# base class's testRunner parameter is not useful because it means
# we have to instantiate HTMLTestRunner before we know self.verbosity.
if self.testRunner is None:
self.testRunner
= HTMLTestRunner(verbosity=self.verbosity)
unittest.TestProgram.runTests(self)

main = TestProgram

##############################################################################
#
Executing this module from the command line
#
#############################################################################

if __name__ == "__main__":
main(module
=None)

Original: https://www.cnblogs.com/qmfsun/p/11558063.html
Author: Agoly
Title: Unitest自动化测试基于HTMLTestRunner报告案例

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/549142/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球