Unittest 笔记:unittest拓展生成HTM报告

HTMLTestRunner 是一个unitest拓展可以生成HTML 报告

下载地址:GitHub: https://github.com/defnnig/HTMLTestRunner

HTMLTestRunner是一个独立的py文件,可以放在Lib 作为第三方模块使用或者作为项目的一部分。

方式1:  验证是否安装成功: 

 如果没有报错说明安装成功 

 方式2 : 作为项目的一部分:

被测试类:  Calculator

unittestdemo1\test_case\calculator.py

# 计算器类
class Calculator:""" 用于完成两个数的加、减、乘、除 """def __init__(self, a, b):self.a = int(a)self.b = int(b)# 加法def add(self):return self.a + self.b# 减法def sub(self):return self.a - self.b# 乘法def mul(self):return self.a * self.b# 除法def div(self):return self.a / self.b

 测试用例类:unittestdemo1&path=test_case/test_calculator_ut.py

TestCalculator
import unittest
from calculator import Calculatorclass TestCalculator(unittest.TestCase):def test_add(self):"""功能:加法:return:"""c = Calculator(3, 5)result = c.add()self.assertEqual(result, 8)print("test_add")def test_sub(self):"""功能: 减法:return:"""c = Calculator(7, 2)result = c.sub()self.assertEqual(result, 5)print("test_sub")def test_mul(self):"""功能: 乘法:return:"""c = Calculator(3, 3)result = c.mul()self.assertEqual(result, 10)def test_div(self):"""功能: 除法:return:"""c = Calculator(6, 2)result = c.div()self.assertEqual(result, 3)print("test_div")if __name__ == '__main__':unittest.main()

  runner_tests.py

测试类的执行是通过 TextTestRunner 类提供run() 方法完成的。

import time
import unittest
from HTMLTestRunner import HTMLTestRunner# # 把测试报告作为附件发送到指定邮箱。
# def send_mail(report):
#     yag = yagmail.SMTP(user="XXXX.com",
#                        password="XXXX",
#                        host='mail.qq.com')
#     subject = "标题,自动化测试报告"
#     contents = "正文,请查看附件。"
#     yag.send('XXXX@qq.com', subject, contents, report)
#     print('email has send out !')if __name__ == '__main__':# 定义测试用例的目录为当前目录test_dir = './test_case'suit = unittest.defaultTestLoader.discover(test_dir, pattern='test_calculator_ut.py')# 取当前日期时间now_time = time.strftime("%Y-%m-%d %H_%M_%S")html_report = './test_report/' + now_time + 'result.html'fp = open(html_report, 'wb')# 调用HTMLTestRunner,运行测试用例runner = HTMLTestRunner(stream=fp,title="百度搜索测试报告",description="运行环境:Windows 10, Chrome浏览器")runner.run(suit)print("run suit")fp.close()#send_mail(html_report)  # 发送报告

 runner = HTMLTestRunner(stream=fp, title="计算器测试报告",description="运行环境:Windows 10, Chrome浏览器")

HTMLTestRunner参数解释

class HTMLTestRunner(Template_mixin):""""""def __init__(self, stream=sys.stdout, verbosity=1, title=None, description=None):

stream: 指定生成报告的文件,必填

verbosity: 日志级别默认为1 ,想得到更详细的可以改为2

title: 标题

description:描述指定测试用例描述

 测试类的下方通过“”“ ”“” 添加用例描述,更易读。

 HTMLTestRunner.py : 

"""
A TestRunner for use with the Python unit testing framework. It
generates a HTML report to show the result at a glance.The simplest way to use this is to invoke its main method. E.g.import unittestimport HTMLTestRunner... define your tests ...if __name__ == '__main__':HTMLTestRunner.main()For more customization options, instantiates a HTMLTestRunner object.
HTMLTestRunner is a counterpart to unittest's TextTestRunner. E.g.# output to a filefp = file('my_report.html', 'wb')runner = HTMLTestRunner.HTMLTestRunner(stream=fp,title='My unit test',description='This demonstrates the report output by HTMLTestRunner.')# Use an external stylesheet.# See the Template_mixin class for more customizable optionsrunner.STYLESHEET_TMPL = '<link rel="stylesheet" href="my_stylesheet.css" type="text/css">'# run the testrunner.run(my_test_suite)------------------------------------------------------------------------
Copyright (c) 2004-2007, Wai Yip Tung
All rights reserved.Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:* Redistributions of source code must retain the above copyright notice,this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyrightnotice, this list of conditions and the following disclaimer in thedocumentation and/or other materials provided with the distribution.
* Neither the name Wai Yip Tung nor the names of its contributors may beused to endorse or promote products derived from this software withoutspecific prior written permission.THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""# URL: http://tungwaiyip.info/software/HTMLTestRunner.html__author__ = "Wai Yip Tung , bugmaster"
__version__ = "0.8.2""""
Change HistoryVersion 0.8.2
* Show output inline instead of popup window (Viorel Lupu).Version in 0.8.1
* Validated XHTML (Wolfgang Borgert).
* Added description of test classes and test cases.Version in 0.8.0
* Define Template_mixin class for customization.
* Workaround a IE 6 bug that it does not treat <script> block as CDATA.Version in 0.7.1
* Back port to Python 2.3 (Frank Horowitz).
* Fix missing scroll bars in detail log (Podi).
"""# TODO: color stderr
# TODO: simplify javascript using ,ore than 1 class in the class attribute?import datetime
import io
import sys
import time
import unittest
from xml.sax import saxutils# ------------------------------------------------------------------------
# The redirectors below are used to capture output during testing. Output
# sent to sys.stdout and sys.stderr are automatically captured. However
# in some cases sys.stdout is already cached before HTMLTestRunner is
# invoked (e.g. calling logging.basicConfig). In order to capture those
# output, use the redirectors for the cached stream.
#
# e.g.
#   >>> logging.basicConfig(stream=HTMLTestRunner.stdout_redirector)
#   >>>class OutputRedirector(object):""" Wrapper to redirect stdout or stderr """def __init__(self, fp):self.fp = fpdef 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)# ----------------------------------------------------------------------
# Templateclass Template_mixin(object):"""Define a HTML template for report customerization and generation.Overall structure of an HTML reportHTML+------------------------+|<html>                  ||  <head>                ||                        ||   STYLESHEET           ||   +----------------+   ||   |                |   ||   +----------------+   ||                        ||  </head>               ||                        ||  <body>                ||                        ||   HEADING              ||   +----------------+   ||   |                |   ||   +----------------+   ||                        ||   REPORT               ||   +----------------+   ||   |                |   ||   +----------------+   ||                        ||   ENDING               ||   +----------------+   ||   |                |   ||   +----------------+   ||                        ||  </body>               ||</html>                 |+------------------------+"""STATUS = {0: 'pass',1: 'fail',2: 'error',}DEFAULT_TITLE = 'Unit Test Report'DEFAULT_DESCRIPTION = ''# ------------------------------------------------------------------------# HTML TemplateHTML_TMPL = r"""<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>%(title)s</title><meta name="generator" content="%(generator)s"/><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/><link rel="stylesheet" href="http://cdn.bootcss.com/bootstrap/3.3.0/css/bootstrap.min.css"><script src="http://cdn.bootcss.com/bootstrap/3.3.0/js/bootstrap.min.js"></script><script src="http://apps.bdimg.com/libs/Chart.js/0.2.0/Chart.min.js"></script><!-- <link href="https://cdn.bootcss.com/echarts/3.8.5/echarts.common.min.js" rel="stylesheet">   -->%(stylesheet)s
</head>
<body>
<script language="javascript" type="text/javascript"><!--
output_list = Array();/* level - 0:Summary; 1:Failed; 2:All */
function showCase(level) {trs = document.getElementsByTagName("tr");for (var i = 0; i < trs.length; i++) {tr = trs[i];id = tr.id;if (id.substr(0,2) == 'ft') {if (level < 1) {tr.className = 'hiddenRow';}else {tr.className = '';}}if (id.substr(0,2) == 'pt') {if (level > 1) {tr.className = '';}else {tr.className = 'hiddenRow';}}}
}function showClassDetail(cid, count) {var id_list = Array(count);var toHide = 1;for (var i = 0; i < count; i++) {tid0 = 't' + cid.substr(1) + '.' + (i+1);tid = 'f' + tid0;tr = document.getElementById(tid);if (!tr) {tid = 'p' + tid0;tr = document.getElementById(tid);}id_list[i] = tid;if (tr.className) {toHide = 0;}}for (var i = 0; i < count; i++) {tid = id_list[i];if (toHide) {document.getElementById('div_'+tid).style.display = 'none'document.getElementById(tid).className = 'hiddenRow';}else {document.getElementById(tid).className = '';}}
}function showTestDetail(div_id){var details_div = document.getElementById(div_id)var displayState = details_div.style.display// alert(displayState)if (displayState != 'block' ) {displayState = 'block'details_div.style.display = 'block'}else {details_div.style.display = 'none'}
}function html_escape(s) {s = s.replace(/&/g,'&amp;');s = s.replace(/</g,'&lt;');s = s.replace(/>/g,'&gt;');return s;
}/* obsoleted by detail in <div>
function showOutput(id, name) {var w = window.open("", //urlname,"resizable,scrollbars,status,width=800,height=450");d = w.document;d.write("<pre>");d.write(html_escape(output_list[id]));d.write("\n");d.write("<a href='javascript:window.close()'>close</a>\n");d.write("</pre>\n");d.close();
}
*/
--></script>%(heading)s
%(report)s
%(ending)s
%(chart_script)s
</body>
</html>
"""# variables: (title, generator, stylesheet, heading, report, ending)# ------------------------------------------------------------------------# Stylesheet## alternatively use a <link> for external style sheet, e.g.#   <link rel="stylesheet" href="$url" type="text/css">STYLESHEET_TMPL = """
<style type="text/css" media="screen">
body        { font-family: verdana, arial, helvetica, sans-serif; font-size: 80%; }
table       { font-size: 100%; }
pre         {  }/* -- heading ---------------------------------------------------------------------- */
h1 {font-size: 16pt;color: gray;
}
.heading {margin-top: 0ex;margin-bottom: 1ex;margin-left: 10px;
}.heading .attribute {margin-top: 1ex;margin-bottom: 0;
}.heading .description {margin-top: 4ex;margin-bottom: 6ex;
}/* -- css div popup ------------------------------------------------------------------------ */
a.popup_link {
}a.popup_link:hover {color: red;
}.popup_window {display: none;position: relative;left: 0px;top: 0px;/*border: solid #627173 1px; */font-family: "Lucida Console", "Courier New", Courier, monospace;text-align: left;font-size: 8pt;width: 500px;
}}
/* -- report ------------------------------------------------------------------------ */
#show_detail_line {margin-top: 3ex;margin-bottom: 1ex;margin-left: 10px;
}
#result_table {width: 80%;border-collapse: collapse;border: 1px solid #777;margin-left: 10px;
}
#header_row {font-weight: bold;color: #606060;background-color: #f5f5f5;border-top-width: 10px;border-color: #d6e9c6;font-size: 12px;
}
#result_table td {border: 1px solid #f5f5f5;padding: 2px;}
#total_row  { font-weight: bold; }
.passClass  { background-color: #d6e9c6; }
.failClass  { background-color: #faebcc; }
.errorClass { background-color: #ebccd1; }
.passCase   { color: #6c6; }
.failCase   { color: #c60; font-weight: bold; }
.errorCase  { color: #c00; font-weight: bold; }
.hiddenRow  { display: none; }
.testcase   { margin-left: 2em; }/* -- ending ---------------------------------------------------------------------- */
#ending {
}/* -- chars ---------------------------------------------------------------------- */
.testChars {margin-left: 150px;}.btn-info1 {color: #fff;background-color: #d6e9c6;border-color: #d6e9c6;
}.btn-info2 {color: #fff;background-color: #faebcc;border-color: #faebcc;
}.btn-info3 {color: #fff;background-color: #ebccd1;border-color: #ebccd1;
}
</style>
"""# ------------------------------------------------------------------------# Heading#HEADING_TMPL = """<div class='heading'>
<h1>%(title)s</h1>
%(parameters)s
<p class='description'>%(description)s</p>
</div><div style="float:left; margin-left: 10px;"><p> Test Case Pie charts </p><a class="btn btn-xs btn-info1">-Pass-</a><br><a class="btn btn-xs btn-info2">-Faild-</a><br><a class="btn btn-xs btn-info3">-Error-</a><br>
</div><div class="testChars"><canvas id="myChart" width="250" height="250"></canvas>
</div>""" # variables: (title, parameters, description)# ------------------------------------------------------------------------# Pie chart#ECHARTS_SCRIPT = """<script type="text/javascript">
var data = [{value: %(error)s,color: "#ebccd1",label: "Error",labelColor: 'white',labelFontSize: '16'},{value : %(fail)s,color : "#faebcc",label: "Fail",labelColor: 'white',labelFontSize: '16'},{value : %(Pass)s,color : "#d6e9c6",label : "Pass",labelColor: 'white',labelFontSize: '16'}			
]var newopts = {animationSteps: 100,animationEasing: 'easeInOutQuart',
}//Get the context of the canvas element we want to select
var ctx = document.getElementById("myChart").getContext("2d");var myNewChart = new Chart(ctx).Pie(data,newopts);</script>"""HEADING_ATTRIBUTE_TMPL = """<p class='attribute'><strong>%(name)s:</strong> %(value)s</p>
""" # variables: (name, value)# ------------------------------------------------------------------------# Report#REPORT_TMPL = """
<p id='show_detail_line' style="margin-left: 10px;">Show
<a href='javascript:showCase(0)' class="btn btn-xs btn-primary">Summary</a>
<a href='javascript:showCase(1)' class="btn btn-xs btn-danger">Failed</a>
<a href='javascript:showCase(2)' class="btn btn-xs btn-info">All</a>
</p>
<table id='result_table'>
<colgroup>
<col align='left' />
<col align='right' />
<col align='right' />
<col align='right' />
<col align='right' />
<col align='right' />
</colgroup>
<tr id='header_row' class="panel-title"><td>Test Group/Test case</td><td>Count</td><td>Pass</td><td>Fail</td><td>Error</td><td>View</td>
</tr>
%(test_list)s
<tr id='total_row'><td>Total</td><td>%(count)s</td><td class="text text-success">%(Pass)s</td><td class="text text-danger">%(fail)s</td><td class="text text-warning">%(error)s</td><td>&nbsp;</td>
</tr>
</table>
""" # variables: (test_list, count, Pass, fail, error)REPORT_CLASS_TMPL = r"""
<tr class='%(style)s'><td>%(desc)s</td><td>%(count)s</td><td>%(Pass)s</td><td>%(fail)s</td><td>%(error)s</td><td><a href="javascript:showClassDetail('%(cid)s',%(count)s)">Detail</a></td>
</tr>
""" # variables: (style, desc, count, Pass, fail, error, cid)REPORT_TEST_WITH_OUTPUT_TMPL = r"""
<tr id='%(tid)s' class='%(Class)s'><td class='%(style)s'><div class='testcase'>%(desc)s</div></td><td colspan='5' align='center'><!--css div popup start--><a class="popup_link" onfocus='this.blur();' href="javascript:showTestDetail('div_%(tid)s')" >%(status)s</a><div id='div_%(tid)s' class="popup_window"><div style='text-align: right; color:red;cursor:pointer'><a onfocus='this.blur();' onclick="document.getElementById('div_%(tid)s').style.display = 'none' " >[x]</a></div><pre>%(script)s</pre></div><!--css div popup end--></td>
</tr>
""" # variables: (tid, Class, style, desc, status)REPORT_TEST_NO_OUTPUT_TMPL = r"""
<tr id='%(tid)s' class='%(Class)s'><td class='%(style)s'><div class='testcase'>%(desc)s</div></td><td colspan='5' align='center'>%(status)s</td>
</tr>
""" # variables: (tid, Class, style, desc, status)REPORT_TEST_OUTPUT_TMPL = r"""
%(id)s: %(output)s
""" # variables: (id, output)# ------------------------------------------------------------------------# ENDING#ENDING_TMPL = """<div id='ending'>&nbsp;</div>"""# -------------------- The end of the Template class -------------------TestResult = unittest.TestResultclass _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 = Noneself.stderr0 = Noneself.success_count = 0self.failure_count = 0self.error_count = 0self.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 = []def startTest(self, test):TestResult.startTest(self, test)# just one buffer for both stdout and stderrself.outputBuffer = io.StringIO()stdout_redirector.fp = self.outputBufferstderr_redirector.fp = self.outputBufferself.stdout0 = sys.stdoutself.stderr0 = sys.stderrsys.stdout = stdout_redirectorsys.stderr = stderr_redirectordef complete_output(self):"""Disconnect output redirection and return buffer.Safe to call multiple times."""if self.stdout0:sys.stdout = self.stdout0sys.stderr = self.stderr0self.stdout0 = Noneself.stderr0 = Nonereturn 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 += 1TestResult.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('.'+str(self.success_count))def addError(self, test, err):self.error_count += 1TestResult.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 += 1TestResult.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):self.stream = streamself.verbosity = verbosityif title is None:self.title = self.DEFAULT_TITLEelse:self.title = titleif description is None:self.description = self.DEFAULT_DESCRIPTIONelse:self.description = descriptionself.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))return resultdef 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 rdef 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)status = []if result.success_count: status.append('Pass %s'    % result.success_count)if result.failure_count: status.append('Failure %s' % result.failure_count)if result.error_count:   status.append('Error %s'   % result.error_count  )if status:status = ' '.join(status)else:status = 'none'return [('Start Time', startTime),('Duration', duration),('Status', status),]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_TMPLdef _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),)return headingdef _generate_report(self, result):rows = []sortedResult = self.sortResult(result.result)for cid, (cls, cls_results) in enumerate(sortedResult):# subtotal for a classnp = nf = ne = 0for n,t,o,e in cls_results:if n == 0: np += 1elif n == 1: nf += 1else: ne += 1# format class descriptionif 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 namerow = 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),)return reportdef _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 chartdef _generate_report_test(self, rows, cid, tid, n, t, o, e):# e.g. 'pt1.1', 'ft1.1', etchas_output = bool(o or e)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 nametmpl = has_output and self.REPORT_TEST_WITH_OUTPUT_TMPL or self.REPORT_TEST_NO_OUTPUT_TMPL# 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 = oelse:uo = oif isinstance(e,str):# TODO: some problem with 'string_escape': it escape \n and mess up formating# ue = unicode(e.encode('string_escape'))ue = eelse:ue = escript = self.REPORT_TEST_OUTPUT_TMPL % dict(id = tid,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 'none'),desc = desc,script = script,status = self.STATUS[n],)rows.append(row)if not has_output:returndef _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 baseclass 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)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/1621307.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

TSC TTP-244条码打印机如何批量打印二维码

二维码的应用可以说是非常的普遍了&#xff0c;二维码在应用之前不但需要条码打印机批量打印二维码&#xff0c;还需要相关的二维码制作软件制作二维码。今天小编就教大家用TSC TTP-244条码打印机批量打印二维码。 1、打开二维码制作软件&#xff0c;新建一个标签&#xff0c;选…

条码打印机如何打印流水号

流水号现在用途也是非常广泛的&#xff0c;应用于各行各业&#xff0c;今天小编就教大家如何用条码打印机打印流水号&#xff0c;操作也是非常简单&#xff0c;先用条码打印软件生成流水号&#xff0c;然后连接条码打印机打印流水号。 打开条码打印软件&#xff0c;新建标签&a…

条码打印软件如何连接激光打印机打印条码标签

在连接打印机打印条码标签之前&#xff0c;需要对条码打印软件有一个简单的了解&#xff0c;条码打印软件是通过驱动来连接各种打印机进行打印条码标签的&#xff0c;所以在连接激光打印机打印条码标签时&#xff0c;需要在电脑上安装通用激光打印机驱动。接下来我们看看过程。…

反转链表+交换两个链表的节点

目录 ​编辑 一&#xff0c;反转链表 1.题目描述 2.例子 3.题目接口 4.分析以及解题代码 1.迭代法 2.递归写法 二&#xff0c;两两交换两个链表中的节点 1.题目描述 2.例子 3.题目接口 4.题目分析以及解法 一&#xff0c;反转链表 1.题目描述 首先来看看反转链表的…

86. 分隔链表(中等系列)

给你一个链表的头节点 head 和一个特定值 x &#xff0c;请你对链表进行分隔&#xff0c;使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。 你应当 保留 两个分区中每个节点的初始相对位置。 示例 1&#xff1a; 输入&#xff1a;head [1,4,3,2,5,2], x 3 输出&…

hiredis的安装与使用

hiredis的介绍 Hiredis 是一个用于 C 语言的轻量级、高性能的 Redis 客户端库。它提供了一组简单易用的 API&#xff0c;用于与 Redis 数据库进行交互。Hiredis 支持 Redis 的所有主要功能&#xff0c;包括字符串、哈希、列表、集合、有序集合等数据结构的读写操作&#xff0c…

Docker vs. Podman: 选择容器技术的智慧之选

嗨&#xff0c;各位亲爱的程序员小伙伴们&#xff01;当我们步入容器技术的世界&#xff0c;往往会在众多选择中迷茫。两个备受瞩目的容器工具&#xff0c;Docker 和 Podman&#xff0c;都在业界掀起了一股风潮。今天&#xff0c;我将带你深入探索&#xff0c;为什么在 Docker …

购买的gmail谷歌邮箱,faceboolhotmail邮箱mail邮箱yahoo,aol在国外使用完全不受影响,购买地址推荐:

购买的谷歌邮箱,faceboolhotmail邮箱mail邮箱yahoo,aol在国外使用完全不受影响&#xff0c;购买地址推荐&#xff1a;邮箱谷歌批发购买地址&#xff1a;buyemail.buyaccountemail.com记好了 登录方法如下 1、下载QQ邮箱手机客户端 2、先使用QQ邮箱登陆到客户端 谷歌邮箱 …

免费激活Yahoo邮箱的POP3服务

通过POP3&#xff0c;我们就能够在本机上使用各种邮件客户端软件(Foxmail、Outlook等)收发电子邮件。 Yahoo免费邮箱没有提供免费POP3服务&#xff0c;而通过邮箱里的设置激活该服务时则被提示需要收费。如图1所示 图1 笔者就给大伙介绍一个小技巧&#xff0c;可以免费地打开Ya…

Foxmail6下@yahoo.cn邮箱设置

http://www.88sina.com/foxmail-yahoo.cn/(转) 昨天申请了一个yahoo.cn的邮箱&#xff0c;在Foxmail中弄了半天&#xff0c;就是使用不了&#xff0c;不是提示输密码就是提示这样那样的错误&#xff0c;今天在网上找来找去&#xff0c;试来试去&#xff0c;终于可以正常收发邮件…

雅虎邮箱 找回密码_如何恢复被遗忘的Yahoo! 密码

雅虎邮箱 找回密码 If you don’t use a password manager, those complex passwords can be pretty hard to remember. If you’ve forgotten your Yahoo password, you can’t really recover that same password, but it’s easy enough to recover your account by resetti…

类似于yahoo邮箱登陆的提示效果

当鼠标聚焦到邮箱地址文本框时&#xff0c;文本框内的“请输入邮箱地址”文字被清空。 效果图&#xff1a; <% Page Language"C#" AutoEventWireup"true" CodeFile"类似于yahoo邮箱登陆的提示效果.aspx.cs" Inherits"类似于yahoo邮箱登…

java雅虎邮件发送

java雅虎邮件发送 1、在网页上登录雅虎邮箱-需翻墙2、登录成功后台&#xff0c;进入账号资料3、进入账户安全&#xff0c;开启双重验证4、创建应用5、替换配置中的邮箱密码即可使用 申请雅虎邮箱后&#xff1a; application.yml配置 spring:mail:host: smtp.mail.yahoo.compo…

【kubernetes】使用kubepshere部署中间件服务

KubeSphere部署中间件服务 入门使用KubeSphere部署单机版MySQL、Redis、RabbitMQ 记录一下搭建过程 (内容学习于尚硅谷云原生课程) 环境准备 VMware虚拟机k8s集群&#xff0c;一主两从&#xff0c;master也作为工作节点&#xff1b;KubeSphere k8skubesphere devops比较占用磁…

Visual Studio 2017安装和项目配置

目录 前言1. What、Why and How1.1 What1.2 Why1.3 How 2. 安装3. 创建新项目4. 配置OpenCV库4.1 下载opencv安装包4.2 配置系统环境变量4.3 VS项目环境配置4.4 总结 5. 已有项目添加6. Tips6.1 常用快捷键6.2 字体和颜色选择6.3 配置编译路径 结语下载链接参考 前言 最近因为项…

scratch3.0接苹果小游戏

Scratch是可视化的编程语言&#xff0c;其丰富的学习环境适合所有年龄阶段的人。利用它可以制作交互式程序、富媒体项目&#xff0c;包括动画故事、读书报告、科学实验、游戏和模拟程序等。与其他编程语言相比&#xff0c;Scratch的可视化编程环境让我们更容易领略编程的魅力 今…

接水果游戏代码 c语言,制作接水果游戏

今天是儿童节&#xff0c;让老师教同学们做个接水果的小游戏吧。 我们新建一个项目&#xff0c;把小猫角色删除&#xff0c;然后选择一个碗的角色来接水果: 把碗移动到白色画布的下半部分&#xff0c;让它可以随着鼠标的移动而左右移动&#xff0c;但是不需要上下移动。方法就是…

游戏黑卡代充36技术及库存系统案例分析

黑卡充值常隐匿于「代充」服务中&#xff0c;且形式多变&#xff0c;从外币汇率差、退款到36漏洞、黑卡/盗刷信用卡充值&#xff0c;甚至还出现了专门的库存系统。 「36漏洞」是利用iOS小额支付漏洞实现的刷单套利业务。苹果为提高用户体验&#xff0c;在 APP Store 购买商品时…