博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Appium python自动化测试系列之使用HTMLTestRunner生成测试报告(十三)
阅读量:5248 次
发布时间:2019-06-14

本文共 17800 字,大约阅读时间需要 59 分钟。

​13.1 测试报告概述

13.1.1 测试报告的定义

在前面章节我们已经讲了自动化基础的很多东西,如果说掌握了,而且自己动手去练习了,我相信在一些初级的面试中是没任何问题的,今天我们接触的应该算是一个比较新的东西,也算是开启另一层知识的大门。

在手工测试过程中如果发现了bug我们需要提交测试报告,自动化中虽然当程序出错的时候我们不可能让程序自动去提交bug(其实也可以,只是需要自己去开发模块,思路:当程序监听到错误的时候就触发一个提交bug的程序),但是为了体现工作的价值当自动化跑完之后是不是就需要生成一份测试报告呢,让我们知道跑了哪些case,哪些通过哪些没通过,通过率是多少。所以在这个情况下我们就有了测试报告

13.1.2 控制台消息和HTML报告的区别

其实很多人不明白为什么有控制台的消息不看,非得看html的报告,那不是抽风么?其实我刚开始做的时候也是一样,觉得控制台的消息一经提示很明确了,而且排错什么的也很好,结合TestNG的看就更方便,其实很长一段时间我确实是这么做的,但是后来有一次领导让我分享一下,我按照平时的工作流程做了,后来的结果是这个需要提高,说:你这个还不能完全叫做自动化。其实当时我想为什么不能呢?后来通过各方面的请教以及收集资料才知道,自己那个真的不叫。就这个很好的例子:每次跑脚本还需要打开IDE然后运行去看报告,不low吗?如果说你的自动化是自动运行,或者执行一个bat,或者是打开一个网址点一个按钮,然后收到的就是一份完整的HTML报告,这样是不是顿时感觉档次上去了呢?可能有人会疑惑,说你报告里面会有运行错误时的一些信息吗?答案肯定是有的。哪个case错误、哪里错误、错误的截图、错误的日志统统的有啦,还有case的通过率,难道这样的报告不比控制台好么?

13.2 如何拥有HTML测试报告

13.2.1 HTMLTestRunner

HTMLTestRunner是python标准库中单元测试模块的一个扩展,在使用python的情况下我们基本都是使用,还有一个事情需要说的是,他是一个扩展,那么就需要自己去安装,当然如果你在python的命令模式下直接引入“import HTMLTestRunner”一下,如果你那个不报错那么代表你有这个环境,不需要另外配置,如果没配置接着下看。

13.2.2 HTMLTestRunner 环境配置

首先我们来看一下我电脑中的配置图片:

从上面的图片我们可以在出在“/Library/Python/2.7/site-packages” 这个目录下面就是我们python的一些扩展包,然后在这个里面我有两个文件,“HTMLTestRunner.py”,“test_HTMLTestRunner.py”,这两个文件就是我们生成html测试报告的时候需要的东西,当然实际上只需要第一个,这个就当作官网的教程吧。大家也可以去下载HTMLTestRunner.py这个文件然后去放到这个目录下面,如果没找到也可以对下面的代码进行复制:

"""A TestRunner for use with the Python unit testing framework. Itgenerates 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 unittest    import 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 file    fp = 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 options    runner.STYLESHEET_TMPL = '
' # run the test runner.run(my_test_suite) ------------------------------------------------------------------------Copyright (c) 2004-2007, Wai Yip TungAll rights reserved. Redistribution and use in source and binary forms, with or withoutmodification, are permitted provided that the following conditions aremet: * 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 copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.* Neither the name Wai Yip Tung nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "ASIS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITEDTO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR APARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNEROR 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, ORPROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDINGNEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THISSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.""" # URL: http://tungwaiyip.info/software/HTMLTestRunner.html __author__ = "Wai Yip Tung"__version__ = "0.8.2" """Change History Version 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 %(heading)s%(report)s%(ending)s """ # variables: (title, generator, stylesheet, heading, report, ending) # ------------------------------------------------------------------------ # Stylesheet # # alternatively use a
for external style sheet, e.g. #
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 # REPORT_TMPL = """

ShowSummaryFailedAll

%(test_list)s
Test Group/Test case Count Pass Fail Error View
Total %(count)s %(Pass)s %(fail)s %(error)s
""" # variables: (test_list, count, Pass, fail, error) REPORT_CLASS_TMPL = r""" %(desc)s %(count)s %(Pass)s %(fail)s %(error)s Detail""" # variables: (style, desc, count, Pass, fail, error, cid) REPORT_TEST_WITH_OUTPUT_TMPL = r"""
%(desc)s
%(status)s
""" # variables: (tid, Class, style, desc, status) REPORT_TEST_NO_OUTPUT_TMPL = r"""
%(desc)s
%(status)s""" # variables: (tid, Class, style, desc, status) REPORT_TEST_OUTPUT_TMPL = r"""%(id)s: %(output)s""" # variables: (id, output) # ------------------------------------------------------------------------ # ENDING # 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 = [] def startTest(self, test): TestResult.startTest(self, test) # just one buffer for both stdout and stderr self.outputBuffer = StringIO.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): 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 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) 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 rmap.has_key(cls): rmap[cls] = [] classes.append(cls) rmap[cls].append((n,t,o,e)) r = [(cls, rmap[cls]) for cls in classes] return r 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) 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() 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 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), ) return heading 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), ) 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) 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 # 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') 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') else: ue = e script = 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: 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)

  记住,这是一个.py文件。配置完毕之后再次去试一下“import HTMLTestRunner”,如果不报错,恭喜你,成功配置文件成功。

 

13.2.3 HTMLTestRunner的使用

首先我们要知道我们定要运行一个case,那么我们是不是首先要将我们的case都封装起来,然后才能去执行呢?

so,这里我们需要讲到开发语言中经常用到的一个关键字 class,就是我们经常说的类,python里面类的定义很简单,class className():这就是一个类的定义。

下面我们来看一个最最最简单的HTMLTestRunner的测试模版是怎么样的

# -*- coding: utf-8 -*-import unittest#引入要测试的文件,就是引入我们测试类所属文件import testMycaseimport HTMLTestRunner   suite = unittest.TestSuite()#引入测试的类,因为我们的类在testMycase这个文件下,所以就直接文件名.类名suite.addTest(unittest.makeSuite(testMycase.appiumTest))#定义报告路径filename = 'test.html'#定义报告文件权限,wb,表示有读写权限fp = file(filename,'wb')runner = HTMLTestRunner.HTMLTestRunner(        stream = fp,        title ='appiumTest',        description = '测试报告')#执行测试runner.run(suite)#关闭文件,否则会无法生成文件fp.close()

  

上面的代码就是我们测试报告生成的一个简要模版,大家只需要将自己需要测试的类引入到这个里面就可以了,当然也是可以直接在方法中去运行的,但是为了方便,这里给大家说了另外一个知识。赶快下去动手吧

 

转载于:https://www.cnblogs.com/Mushishi_xu/p/7797902.html

你可能感兴趣的文章
Flask之自定义模型类
查看>>
2.8 GO 参数传递
查看>>
C++ Primer 第四版阅读笔记
查看>>
Spring Boot + RabbitMQ 使用示例
查看>>
openLDAP环境搭建
查看>>
===
查看>>
建议将网页大小调至 110% 食用。
查看>>
Spring和Mybatis的集成
查看>>
玩转UICollectionViewLayout
查看>>
如何在.xml文件中配置Servlet信息
查看>>
使用AVCaptureSession捕捉静态图片
查看>>
redis enable TLS
查看>>
bugku web 头等舱
查看>>
Codeforces Round #436 (Div. 2)【A、B、C、D、E】
查看>>
js 异步加载的方法
查看>>
java学习之多态(转型、特点)
查看>>
十五 枚举
查看>>
列表list
查看>>
实习生的工作周报大纲
查看>>
最优惠买哈利波特书
查看>>