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:\report_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 %}

  


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com