2019-08-19

[cp]如何自己实现一个HTMLRunner


在使用unittest框架时,我们常常需要下载一个HTMLRunnerCN.py用来生成HTML格式的报告,那么我们能不能自己实现一个呢?


HTMLRunner是模仿unittest自带的TextTestRunner()实现的,我们先来看看TextTestRunner()的运行流程。


TextTestRunner使用方法

import unittest


suite = unittest.defaultTestLoader.discover("./")


with open("report.txt", "w") as f:  # 将运行结果保存为txt文件

    unittest.TextTestRunner().run(suite)

运行流程

        1.TextTestRunner 内部实现了一个TextTestResult(继承自unittest.TestResult类)来记录测试结果

        2.TextTestRunner().run()实际调用suite(result)既suite.run(result) (result用来记录结果)

        3.suite.run(result)会遍历suite中的用例,依次调用case(result)既case.run(result)

        4.case.run(result)时,首先会调用result.testRun+=1然后执行用例方法testMethod(), 如果用例失败、出错、跳过则用例会分别调用result.addSuccess(),result.addFailure()等方法,在对应的result.failures,result.errors列表中添加用例信息,默认成功用例result中不处理

        5.运行完返回result(测试结果对象)


unittest.TextTestRunner和网上的HTMLRunner都是基于stream流去写的文件,每执行一条用例,把对应的结果和信息写到流中,最后输出成文件,这种方法需要很多的细节控制,比较复杂。

我们可以采用解析执行完返回result结果,通过Jinjia2模板引擎渲染,将数据渲染到模板里,形成报告文件。


Jinjia2是一个三方包,可以将模板代码中的{{变量名}}等占位符将变量值渲染进去,支持循环和if判断。安装方法pip install jinjia2


实现步骤

1.首先我们要写个模板


TPL = '''

<!DOCTYPE html>

<html lang="en">

    <head>

        <meta charset="UTF-8">

        <title>{{title}}</title>

    </head>

    <body>

        <h2>{{title}}</h2>

        <h3>{{description}}</h3>

        <br/>

        <table border="1">

            {% for case in cases %}

            <tr>

                <td>{{case.name}}</td>

                <td>{{case.status}}</td>

                <td>{{case.exec_info}}</td>

            </tr>

            {% endfor %}

        </table>

    </body>

</html>

'''

            1.{{title}},{{description}}能将传入的数据中的相应的变量值填充进去

            2.{% for case in cases%} ...{% endfor %}遍历cases列表中每一个用例数据,每个生成一个表格行(<tr>...</tr>)

2.自定义一个Result类

由于默认的TestResult()将各种状态的用例分散存的,我们可以自定义一个Result类来处理用例成功、失败、出错执行的操作


class Result(unittest.TestResult):

    def __init__(self):

        super().__init__()

        self.cases = []


    def addSuccess(self, test):

        self.cases.append({"name": test.id(), "status": "pass", "exec_info": ""})


    def addError(self, test, exec_info):

        self.cases.append({"name": test.id(), "status": "error",

                            "exec_info": self._exc_info_to_string(exec_info, test)

                          .replace("\n", "<br/>")})


    def addFailure(self, test, exec_info):

        self.cases.append({"name": test.id(), "status": "fail",

                            "exec_info": self._exc_info_to_string(exec_info, test)

                          .replace("\n", "<br/>")})


    def addSkip(self, test, reason):

        self.cases.append({"name": test.id(), "status": "skip", "exec_info": reason))


          1.addSuccess等方法对应用例成功或其他状态时在result结果中的操作

          2._exec_info_to_string: 默认用例传过来的exec_info是Trackback对象

,需要转换为字符串,replace将\n转为网页的换行<br/>

3.实现我们的HTMLRunner

class HTMLRunner(object):

    def __init__(self, output, title="Test Report", description=""):

        self.file = output

        self.title = title

        self.description = description


    def run(self, suite):

        result = Result()  # 用于保存测试结果

        suite(result)  # 执行测试


        # 渲染数据到模板

        content = Template(TPL).render({"title": self.title,

                                        "description": self.description,

                                        "cases": result.cases})

        with open(self.file, "w") as f:

            f.write(content)  # 写入文件

        return result


使用方法(自己准备几条用例)


suite = unittest.defaultTestLoader.discover("./")

HTMLRunner(output="report.html",

          title="测试报告",

          description="测试报告描述").run(suite)


生成的测试报告(如图

图片发自简书App
图片发自简书App

)

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,744评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,505评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,105评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,242评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,269评论 6 389
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,215评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,096评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,939评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,354评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,573评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,745评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,448评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,048评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,683评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,838评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,776评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,652评论 2 354

推荐阅读更多精彩内容