htmlrunner用法_如何自己实现一个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)

运行流程

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

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

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

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

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

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

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

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

实现步骤

首先我们要写个模板

TPL = '''

{{title}}

{{title}}

{{description}}

{% for case in cases %}

{{case.name}}{{case.status}}{{case.exec_info}}

{% endfor %}

'''

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

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

...)

自定义一个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", "
")})

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", "
")})

def addSkip(self, test, reason):

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

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

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

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

实现我们的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)

生成的测试报告

整体代码

美化格式,增加执行统计信息

import time

import unittest

from jinja2 import Template

TPL = '''

{{title}}

测试报告

测试报告描述信息
执行: {{run_num}} 通过: {{pass_num}} 失败: {{fail_num}} 出错: {{error_num}} 跳过: {{skipped_num}}
执行时间: {{duration}}s

用例名状态执行信息

{% for case in cases %}

{{case.name}}{{case.status}}{{case.exec_info}}

{% endfor %}

'''

class Result(unittest.TestResult):

def __init__(self):

super().__init__()

self.success = []

self.cases = []

def addSuccess(self, test):

self.success.append(test)

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

def addError(self, test, exec_info):

self.errors.append((test, exec_info))

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

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

.replace("\n", "
")})

def addFailure(self, test, exec_info):

self.failures.append((test, exec_info))

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

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

.replace("\n", "
")})

def addSkip(self, test, exec_info):

self.skipped.append((test, exec_info))

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

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

.replace("\n", "
")})

def addExpectedFailure(self, test, exec_info):

self.success.append(test)

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

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

.replace("\n", "
")})

def addUnexpectedSuccess(self, test):

self.failures.append((test, "UnexpectedSuccess"))

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

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() # 用于保存测试结果

start_time = time.time()

suite(result) # 执行测试

duration = round(time.time() - start_time, 6)

print(len(result.success), len(result.failures))

# 渲染数据到模板

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

"description": self.description,

"cases": result.cases,

"run_num": result.testsRun,

"pass_num": len(result.success),

"fail_num": len(result.failures),

"skipped_num": len(result.skipped),

"error_num": len(result.errors),

"duration": duration})

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

f.write(content) # 写入文件

return result

if __name__ == "__main__":

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

HTMLRunner(output="report.html",

title="测试报告",

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

Python测试交流,欢迎添加作者微信:lockingfree

在这个代码片段中,有几个错误出现了。首先,引用中的错误是由于在写入CSV文件时,需要传入一个字节对象,而不是字符串对象。换句话说,你需要将字符串转换为字节。其次,引用和引用中的错误是由于没有定义ddt这个变量或模块而造成的。所以,你需要确保在使用ddt之前进行正确的导入或定义。 为了解决这些问题,你可以按照以下步骤操作: 1. 引用的问题:在写入CSV文件时,你需要将字符串转换为字节。你可以使用encode()方法来实现这一点,例如将字符串转换为UTF-8编码的字节。你可以修改代码如下: writer.writerow([b'element', b'system']) 2. 引用和引用的问题:在使用ddt之前,你需要确保正确导入或定义ddt模块或变量。你可以通过添加以下导入语句来导入ddt模块: from ddt import ddt 或者,如果ddt是你自己定义的变量,你需要在使用之前先定义它。 请注意,这些解决方案仅提供了修复错误的方法,但是要确保代码的其他部分没有其他错误或逻辑问题。另外,如果你的代码依赖于其他模块或库,请确保你已经正确导入它们。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [【python】写csv文件时遇到的错误](https://blog.csdn.net/weixin_30642267/article/details/99755098)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Python+unittest+requests+DDT+Htmlrunner全自动化接口测试](https://blog.csdn.net/VSXJA/article/details/107078325)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值