HTMLTestRunner测试报告优化
欢迎关注公众号[喵先生课堂]
HTMLTestRunner.py下载(https://github.com/Gelomen/HTMLTestReportCN-ScreenShot)
创建HTMLTestRunner测试项目:
新建python项目test01,在项目中新建 test_case.py模块,用来写测试case。
下HTMLTestRunner.py]https://github.com/Gelomen/HTMLTestReportCN-ScreenShot/blob/master/src/lib/HTMLTestReportCN.py)并保存到项目中,命名为HTMLTestRunner.py。
新建run.py文件用来编写执行case脚本。
创建report文件夹,用来存放生成的测试报告
打开test_case.py 模块添加如下case代码:
import unittest
class TestDemo(unittest.TestCase):
def test_one(self):
assert 1 == 1
def test_two(self):
assert 'H' in "Helloword!"
def test_three(self):
assert 5 == 10
打开run.py模块,添加如下代码:
import os
import time
from HTMLTestRunner import HTMLTestRunner
from test_case import TestDemo
import unittest
# 项目根目录
base_path = os.path.dirname(os.path.abspath(__file__))
# 测试报告存放目录
report_path = os.path.join(base_path, "report")
# 测试报告名称
report_filename = os.path.join(report_path, str(time.strftime("%Y%m%d%H%M%S", time.localtime())) + ".html")
# 创建测试集合
case_suite = unittest.TestSuite()
case_suite.addTest(TestDemo("test_one"))
case_suite.addTest(TestDemo("test_two"))
case_suite.addTest(TestDemo("test_three"))
# 使用HTMLTestRunner运行测试并生成测试报告
def start():
with open(report_filename, 'wb') as file:
runner = HTMLTestRunner(stream=file, title='自动化测试报告', description='用例执行情况:')
runner.run(case_suite)
if __name__ == '__main__':
start()
运行run.py后在report文件夹下生成一个以 .html结尾的测试报告
通过浏览器打开该HTML测试报告,样子如下:
到此为止我们的项目准备工作完成,开始进行Html测试报告的优化工作
测试报告插入log:
通过测试报告可以看出,执行失败的case可以在测试报告中看到错误信息,但执行通过的case却没有信息输出。现在我们要将log信息打印进测试报告中。
* 添加log模块:
首先我们需要在case中打印log,为了更好的进行log输出,我们在项目中新建 log.py文件,随后再新建Log文件夹用来存放log文件。
* log模块封装:
打开log.py文件,复制下面代码并添加
# !/usr/bin/python
# -*- coding:utf-8 -*-
import logging
import os.path
import time
class Logger(object):
# 初始化加载
def __init__(self):
# 创建一个 logger 对象
self.logger = logging.getLogger("test") # loggger 对象为被执行的对象类
self.logger.setLevel(logging.DEBUG) # 设置日志模式为调试模式
# 创建一个 handler,用于写入日志文件
rq = time.strftime('%Y%m%d%H%M', time.localtime(time.time())) # 设置日期格式
log_path = os.path.join(os.getcwd(),'log/')
# 判断 log 文件夹是否创建,未创建则进行创建
isExists = os.path.exists(log_path)
if not isExists:
try:
os.makedirs(log_path)
except Exception as e:
print("创建文件夹失败", e)
log_name = log_path + rq + '.log'
fh = logging.FileHandler(log_name)
fh.setLevel(logging.INFO)
# 创建一个 handler,用于输出到控制台
ch = logging.StreamHandler()
ch.setLevel(logging.INFO)
# 定义 handler 输出格式
formatter = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(process)d - %(processName)s - %(message)s ')
fh.setFormatter(formatter)
ch.setFormatter(formatter)
# 给logger 添加 handler
self.logger.addHandler(fh)
self.logger.addHandler(ch)
def d(self, msg, *args, **kwargs):
self.logger.debug(msg, *args, **kwargs)
def i(self, msg, *args, **kwargs):
self.logger.info(msg, *args, **kwargs)
def w(self, msg, *args, **kwargs):
self.logger.warning(msg, *args, **kwargs)
def c(self, msg, *args, **kwargs):
self.logger.critical(msg, *args, **kwargs)
def e(self, msg, *args, **kwargs):
self.logger.error(msg, *args, **kwargs)
此时我们在 test_case.py模块中添加一些log信息
import unittest
from log import Logger
log=Logger()#为了简单演示,log初始化暂时放在了这里
class TestDemo(unittest.TestCase):
def test_one(self):
log.i("case name:test_one")
assert 1 == 1
def test_two(self):
log.i("case name:test_two")
assert 'H' in "Helloword!"
def test_three(self):
log.i("case name:test_three")
assert 5 == 10
运行run.py文件,此时我们可以在控制台输出的log信息,同时在 log/文件夹下也可以看到生成的.log文件,但测试报告中还是没显示log信息,
控制台log:
2021-12-14 15:23:39,614 - test - INFO - 17952 - MainProcess - case name:test_one
S test_one (test_case.TestDemo)
2021-12-14 15:23:39,614 - test - INFO - 17952 - MainProcess - case name:test_two
S test_two (test_case.TestDemo)
2021-12-14 15:23:39,615 - test - INFO - 17952 - MainProcess - case name:test_three
F test_three (test_case.TestDemo)
--------------------- 测试结束 ---------------------
------------- 合计耗时: 0:00:00.000980 -------------
log/文件夹中的log信息:
开始在测试报告中添加log信息:
想要在测试报告中也输出log信息,需要对HTMLTestRunner.py进行修改,打开HTMLTestRunner.py文件。
- 首先导入logging模块
- 找到 class _TestResult(TestResult):,在init方法中添加
self.logger = logging.getLogger('test')
如下:
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):
... ... ...
... ... ...
self.logger = logging.getLogger('test')
- 在 def startTest(self, test): 方法后面添加如下代码:
def startTest(self, test):
stream = sys.stderr
# stdout_content = " Testing: " + str(test)
# stream.write(stdout_content)
# stream.flush()
# stream.write("\n")
TestResult.startTest(self, test)
# just one buffer for both stdout and stderr
self.outputBuffer = io.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
self.test_start_time = round(time.time(), 2)
# ---添加 logging 输出以及格式化----
self.log_cap = io.StringIO()
self.ch = logging.StreamHandler(self.log_cap)
self.ch.setLevel(logging.DEBUG)
formatter = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(process)d - %(processName)s - %(message)s ')
self.ch.setFormatter(formatter)
self.logger.addHandler(self.ch)
如图:
- 找到 def complete_output(self):函数,在函数的返回值中加入logging存在内存中的输出,用换行符隔开。
def complete_output(self):
"""
Disconnect output redirection and return buffer.
Safe to call multiple times.
"""
self.test_end_time = round(time.time(), 2)
if self.stdout0:
sys.stdout = self.stdout0
sys.stderr = self.stderr0
self.stdout0 = None
self.stderr0 = None
#---添加 log out put ---
return self.outputBuffer.getvalue() + '\n' + self.log_cap.getvalue()
如图:
- 每个用例执行完后,清除handler,在stopTest函数中加入代码:
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.
# --- 清除log的handle ---
self.complete_output()
self.logger.removeHandler(self.ch)
如图:
此时以修改完毕,我们保存后再次运行run.py生成新的测试报告并打开,可以看到 "通过"状态的case也展示了log信息
项目整体结构如下:
欢迎关注公众号[喵先生课堂]