zoukankan      html  css  js  c++  java
  • nose测试中修改nose_html_reporting插件,使生成的html报告加入显示截图功能

    使用nose框架在测试WEB UI自动化时,使用了第三方插件nose-html-reporting,来生成HTML报告,nose-html-reporting具体使用参见管网https://pypi.python.org/pypi/nose-html-reporting

    但在真实使用测试时,经常会将错误截图,但nose-html-reporting只显示错误日志,不太直观,怎么将错误截图也加入到HMTL报告中呢,google了一把也没有答案。那就自己动手吧。

    一、首先看看原始的报告,如下

    二、需求

    我们加一列在失败或错误时,有图片链接,在成功时没有。

    解决思路:从截图存储的文件夹中,遍历与测试名称一致的文件,如果有,则显示链接,没有则空。

    三、实现

    先看看nose_html_reporting插件怎么实现输出HTML的

    安装好插件后,查看对应的目录,只有__init__.py和template/report.html、template/report2.jinja2几个文件

    在查看__int__.py文件后,从下面两段代码中,我们可以知道,html是通过report2.jinja2模板生成的

    parser.add_option(
                '--html-report-template', action='store',
                dest='html_template', metavar="FILE",
                default=env.get('NOSE_HTML_TEMPLATE_FILE',
                                os.path.join(os.path.dirname(__file__), "templates", "report2.jinja2")),
                help="Path to html template file in with jinja2 format."
                     "Default is report.html in the lib sources"
                     "[NOSE_HTML_TEMPLATE_FILE]")
    
    ......
    
    
    self.stats['total'] = sum(self.stats.values())
            for group in self.report_data.values():
                group.stats['total'] = sum(group.stats.values())
            self.report_file.write(self.jinja.get_template(os.path.basename(self.report_template_filename)).render(
                report=self.report_data,
                stats=self.stats,
                rawoutput=self._format_output(self.complete_global_output())
            ))
    

     1、修改report2.jinja2模版,加入可以显示链接的一列

    我们在time后面加一列,用于显示错误图片链接,红色行。

    <tr id='{{ class + test.name }}' class='testcase'>
                <td class="{{ test_status.lower() }}Case">
                    {{ test.name }}
                    {% if test.shortDescription %}
                        <div class="shortDescription">
                            {{ test.shortDescription }}
                        </div>
                    {% endif %}
                </td>
                <td>{{ test.time }}</td>
                <td><p><a href="{{test.dir}}{{test.snap}}">{{ test.snap }}</a></td>
                <td colspan='4' align='center'>
                <!--css div popup start-->

    2、修改__init__.py文件,传入截图存储文件夹参数及处理图片链接参数

    加入截图文件夹options参数

    def options(self, parser, env):
            """Sets additional command line options."""
            Plugin.options(self, parser, env)
            parser.add_option(
                '--html-report', action='store',
                dest='html_file', metavar="FILE",
                default=env.get('NOSE_HTML_FILE', 'nosetests.html'),
                help="Path to html file to store the report in. "
                     "Default is nosetests.html in the working directory "
                     "[NOSE_HTML_FILE]")
            parser.add_option(
                '--html-report-template', action='store',
                dest='html_template', metavar="FILE",
                default=env.get('NOSE_HTML_TEMPLATE_FILE',
                                os.path.join(os.path.dirname(__file__), "templates", "report2.jinja2")),
                help="Path to html template file in with jinja2 format."
                     "Default is report.html in the lib sources"
                     "[NOSE_HTML_TEMPLATE_FILE]")
    
            parser.add_option(
                '--snap-dir', action='store',
                dest='snap_dir', metavar="FILE",
                default="c:\report",
                help="snap-dir.")
    def configure(self, options, config):
            """Configures the xunit plugin."""
            Plugin.configure(self, options, config)
            self.config = config
            if self.enabled:
                self.jinja = Environment(
                    loader=FileSystemLoader(os.path.dirname(options.html_template)),
                    trim_blocks=True,
                    lstrip_blocks=True
                )
                self.stats = {'errors': 0, 'failures': 0, 'passes': 0, 'skipped': 0}
                self.report_data = defaultdict(Group)
                htmlfile_dirname = os.path.dirname(options.html_file)
                if not os.path.exists(os.path.abspath(htmlfile_dirname)):
                    os.makedirs(htmlfile_dirname)
                self.report_file = codecs.open(options.html_file, 'w', self.encoding, 'replace')
                self.report_template_filename = options.html_template
                self.snap_dir = options.snap_dir

    修改错误和fail时,加入图片文件名

    def addError(self, test, err, capt=None):
            """Add error output to Xunit report.
            """
            exc_type, exc_val, tb = err
            tb = ''.join(traceback.format_exception(
                exc_type,
                exc_val if isinstance(exc_val, exc_type) else exc_type(exc_val),
                tb
            ))
            name = id_split(test.id())
            group = self.report_data[name[0]]
            if issubclass(err[0], SkipTest):
                type = 'skipped'
                self.stats['skipped'] += 1
                group.stats['skipped'] += 1
            else:
                type = 'error'
                self.stats['errors'] += 1
                group.stats['errors'] += 1
            group.tests.append({
                'name': name[-1],
                'failed': True,
                'type': type,
                'dir':self.snap_dir,
                'errtype': nice_classname(err[0]),
                'message': exc_message(err),
                'tb': self._format_output(tb),
                'output': self._format_output(self.complete_test_output(exc_message(err), tb)),
                'shortDescription': test.shortDescription(),
                'time': str(datetime.now() - self.test_start_time),
                'snap': "".join([x for x in os.listdir(self.snap_dir) if x==name[-1]]),
            })
    def addFailure(self, test, err, capt=None):
            """Add failure output to Xunit report.
            """
            exc_type, exc_val, tb = err
            tb = ''.join(traceback.format_exception(
                exc_type,
                exc_val if isinstance(exc_val, exc_type) else exc_type(exc_val),
                tb
            ))
            name = id_split(test.id())
            group = self.report_data[name[0]]
            self.stats['failures'] += 1
            group.stats['failures'] += 1
            group.tests.append({
                'name': name[-1],
                'failed': True,
                'dir':self.snap_dir,
                'errtype': nice_classname(err[0]),
                'message': exc_message(err),
                'tb': self._format_output(tb),
                'output': self._format_output(self.complete_test_output(exc_message(err), tb)),
                'shortDescription': test.shortDescription(),
                'time': str(datetime.now() - self.test_start_time),
                'snap': "".join([x for x in os.listdir(self.snap_dir) if x==name[-1]]),
            })

    四、测试使用

    修改完__init__.py后,我们通过nosetests -h,我们可以看到多了一个参数:

    首先写个测试程序,如下:

    #coding:utf-8
    
    from selenium import webdriver
    import inspect
    driver = webdriver.Firefox()
    
    def test_001():
        assert 2==1
        
    
    def test_0002():
        assert 3==1
    
    def test_learn_3():
        try:
            driver.get("http://www.baidu.com")
            driver.find_element_by_id("xx")
        except Exception,e:
            driver.get_screenshot_as_file("c:\report_1\%s" % (inspect.stack()[0][3]))
            raise
    View Code

    在使用nose测试,因为在刚刚的程序中,我们截图保存在c:\report_1这个目录,所以测试使用如下:

    C:>nosetests -v nose_test.py --with-html --snap-dir="c:
    eport_1"

    最后生成的HTML报告如下:

    time后面多了一列,是失败时的截图链接,点击test_lean_3后,浏览器会自动跳转至截图显示。

    大功告成。。。。。。

    在实际的自动化代码中,你还需要加入清理资源的功能,把截图都清理或移至其它地方,不然截图会覆盖或显示上次结果

    cnblogs不能上传附件,如果需要源码,可以联系我。

    -----后期优化了下,把jinja2模板改了下,直接在html中显示缩略图,链接显示大图

    {% if test_status == 'Fail' or test_status == 'Error' %}
                    <td><p><a href="{{test.dir}}{{test.snap}}" title="link to datu"><img src="{{test.dir}}{{test.snap}}" width="165" height="60" /></a></p></td>
    {%- endif %}
    

      

  • 相关阅读:
    使用RestTemplate发送post请求,请求头中封装参数
    LocalDateTime的一些用法
    java实现遍历文件目录,根据文件最后的修改时间排序,并将文件全路径存入List集合
    【Quartz】Quartz存储与持久化-基于quartz.properties的配置
    《分布式任务调度平台XXL-JOB》
    SpringBoot集成Quartz实现定时器
    springboot整合Quartz实现动态配置定时任务
    Java读取文件创建时间和最后修改时间
    杂七杂八快捷键🍿
    git命令笔记
  • 原文地址:https://www.cnblogs.com/landhu/p/6023971.html
Copyright © 2011-2022 走看看