pytest-html报告优化实战

1、在我们实际工作中,环境信息不一定要在报告中详细提现,可以增减

2、用例信息,默认展示的是用例的model名::用例名称,并不直观,所以我们可以增加一个用例描述,直观描述用例的测试内容

3、links列没有用到,可以删除

4、logs的作用往往是为了报错或者用例执行失败后调试用的,所以在用例稳定运行且成功的情况下可以去掉。
接下来我们就来针对以上4点,对我们的测试报告进行优化

测试报告优化

测试报告格式优化,所有内容均需要在conftest.py中配置
首先引入以下包

from py.xml import html
import pytest

环境信息增减

conftest.py 中增加以下代码,具体需要增加和去除的信息根据个人需要调整。

修改Environment项目展示的信息

def pytest_configure(config):
    # 添加项目名称
    config._metadata["项目名称"] = "钣喷车间小程序测试"
    # 删除Java_Home
    config._metadata.pop("JAVA_HOME")
    # 删除Plugins
    config._metadata.pop("Plugins")

添加Summary项目展示的信息

@pytest.mark.optionalhook
def pytest_html_results_summary(prefix):  #添加summary内容
    prefix.extend([html.p("所属部门: test")])
    prefix.extend([html.p("测试人员: jack")])

增加用例描述和去除link列

@pytest.mark.optionalhook
def pytest_html_results_table_header(cells):
    cells.insert(1, html.th('Description'))  # 表头添加Description
    cells.pop(-1)  # 删除link


@pytest.mark.optionalhook
def pytest_html_results_table_row(report, cells):
    cells.insert(1, html.td(report.description))  #表头对应的内容
    cells.pop(-1)  # 删除link列


@pytest.mark.hookwrapper
def pytest_runtest_makereport(item, call):  #description取值为用例说明__doc__
    outcome = yield
    report = outcome.get_result()
    report.description = str(item.function.__doc__)

注:用例的description取值为对应用例的说明

去除执行成功用例的log输出

@pytest.mark.optionalhook
def pytest_html_results_table_html(report, data):   #清除执行成功的用例logs
    if report.passed:
        del data[:]
        data.append(html.div('自定义用例pass展示的log.', class_='empty log'))

增加错误截图

应用场景

在我们做UI自动化时,往往在用例执行失败时通过设定的log来进行错误分析,来优化代码或者确定问题,测试报告也默认只有log的展示。如果我们在用例执行失败时能进行当前页面的截图,并且将截图直接呈现在测试报告中的话,是不是可以帮助我们更直观的定位到问题呢?

实现方式

同样是在conftest.py中进行配置:

# 定义一个全局变量,用于存储内容
global_data = {}


@pytest.fixture
def set_global_data():
    """
    设置全局变量,用于关联参数
    :return:
    """
    def _set_global_data(key, value):
        global_data[key] = value
    return _set_global_data


@pytest.fixture
def get_global_data():
    """
    从全局变量global_data中取值
    :return:
    """
    def _get_global_data(key):
        return global_data.get(key)
    return _get_global_data


# 用例失败截图
@pytest.mark.hookwrapper
def pytest_runtest_makereport(item):
    """
    当测试失败的时候,自动截图,展示到html报告中
    :param item:
    """
    pytest_html = item.config.pluginmanager.getplugin('html')
    outcome = yield
    report = outcome.get_result()
    extra = getattr(report, 'extra', [])
    if report.when == 'call' or report.when == "setup":
        xfail = hasattr(report, 'wasxfail')
        if (report.skipped and xfail) or (report.failed and not xfail):
            file_name = report.nodeid.replace("::", "_") + ".png"
            screen_img = _capture_screenshot()
            if file_name:
                html = '<div><img src="data:image/png;base64,%s" alt="screenshot" style="width:600px;height:300px;" ' \
                       'onclick="window.open(this.src)" align="right"/></div>' % screen_img
                extra.append(pytest_html.extras.html(html))
        report.extra = extra
        report.description = str(item.function.__doc__)


def _capture_screenshot():
    """截图保存为base64"""
    return global_data['driver'].get_screenshot_as_base64()

其他地方调用

class TestCase:
    @pytest.fixture(autouse=True, scope='function')
    def openApp(self, set_global_data):
        self.driver = webdriver.Remote(
            command_executor='http://127.0.0.1:4723/wd/hub',
            desired_capabilities={
                "platformName": "ios",
                "appium:deviceName": "xxxxxxx",
                "appium:platformVersion": "15.7.1",
                "appium:bundleId": "com.xxx.xxx",
                "appium:udid": "xxxxxxxxxxxx",
                'unicodeKeyboard': True,
                'resetKeyboard': True
            }
        )

        # 设置全部变量driver,提供调用
        set_global_data('driver', self.driver)

获取用例执行的统计数据

应用场景

以上为测试报告中的统计数据,有时我们可能想直接把统计数据提取出来,单独发送邮件时展示,或者作为直观的执行结果进行传递,而不需要别人要打开测试报告才能看到。那这个时候我们应该怎么做呢?

实现方式

同样是在conftest.py中进行配置:

def pytest_terminal_summary(terminalreporter, exitstatus, config):
    '''收集测试结果'''
    total = terminalreporter._numcollected
    passed = len([i for i in terminalreporter.stats.get('passed', []) if i.when != 'teardown'])
    failed = len([i for i in terminalreporter.stats.get('failed', []) if i.when != 'teardown'])
    error = len([i for i in terminalreporter.stats.get('error', []) if i.when != 'teardown'])
    skipped = len([i for i in terminalreporter.stats.get('skipped', []) if i.when != 'teardown'])
    pass_rate = format(len(terminalreporter.stats.get('passed', []))/terminalreporter._numcollected*100, '.2f')

    duration = time.time() - terminalreporter._sessionstarttime
    total_times = str(format(duration,'.2f')) + '秒'   #时间取2位小数,单位为秒

    count = f'本次用例执行结果概览:\n\n用例合计数:-----{total}\n执行通过数:-----{passed}\n执行失败数:-----{failed}\n执行报错数:-----{error}\n跳过用例数:-----{skipped}\n执行成功率:-----{pass_rate}%\n运行总耗时:-----{total_times}\n\n详细测试报告请查阅附件'

    set_global_data('summary', count) #将组装好的summary文本内容设置为全部变量,已供其他地方调用

在需要用到统计数据的地方直接调用,就可以把统计数据获取到。

global_data['summary']

效果展示(邮件正文发送):

posted @ 2023-02-15 15:07  郭小睿  阅读(144)  评论(0编辑  收藏  举报