Python生成html报告集成错误截图、重复执行用例、用例执行顺序、多重断言
  VxbKCNpUI3P6 2023年11月18日 30 0

一、pytest-html(生成html报告)

1.1.安装

在命令行中运行以下命令进行安装:目录最新的版本是4.0.2这个版本有bug,通过pytest.ini生成测试报告,会报错

pip install pytest-html==2.1.1

或者(使用国内的豆瓣源,数据会定期同步国外官网,速度快。)

pip install pytest-html==2.1.1 -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com

1.2.操作参数

命令行参数:

  • --html=report.html(普通HTML报告,CSS是独立的,分享报告的时候样式会丢。)
  • --html=report.html --self-contained-html(合并CSS的HTML报告,分享报告样式不丢失,如:分享发邮件展示报告。)

1.3.在测试报告中集成错误截图

在执行web自动化的时候,希望测试用例失败时,以截图的方式展示在html报告里。

1.3.1.修改conftest.py文件:

在测试用例包下创建conftest.py,利用勾子函数进行错误异常截图,代码如下:

from selenium import webdriver
import pytest
import base64

driver = None

@pytest.mark.hookwrapper
def pytest_runtest_makereport(item):
    """
    当测试失败的时候,自动截图,展示到html报告中
    """
    # 获取 pytest-html 插件实例,以便在之后的代码中使用 pytest-html 提供的功能。
    pytest_html = item.config.pluginmanager.getplugin('html')
    # 用于执行生成器并获取到其返回的结果。
    outcome = yield
    # 从 outcome 中获取测试报告结果。
    report = outcome.get_result()
    # 用于获取测试报告的 extra 属性,如果没有 extra 属性,则新建一个空的列表。
    extra = getattr(report, 'extra', [])

    # 判断测试报告的执行时间是否为 “call” 或 "setup",即在测试调用或测试设置期间发生。
    if report.when == 'call' or report.when == "setup":
        # 检查测试报告是否有 wasxfail 属性,用于标记测试是否被预期失败。
        xfail = hasattr(report, 'wasxfail')
        # 检查测试报告是否为跳过的测试(并且被标记为预期失败)或者失败的测试(并且没有被标记为预期失败)。
        if (report.skipped and xfail) or (report.failed and not xfail):
            # 根据测试报告的 nodeid 创建一个截图文件名,将双冒号替换为下划线。
            file_name = report.nodeid.replace("::", "_")+".png"
            # 调用名为 _capture_screenshot() 的函数来获取屏幕截图的二进制数据。
            screen_img = _capture_screenshot()
            # 检查截图文件名和屏幕截图数据是否存在。
            if file_name and screen_img:
                # 将屏幕截图数据进行 base64 编码,并将结果解码为字符串。
                screenshot_base64 = base64.b64encode(screen_img).decode("utf-8")
                # 创建一个 HTML 标签,其中包含 base64 编码后的屏幕截图作为图片的源。
                html_content = '<div><img src="data:image/png;base64,{}" alt="screenshot" style="width:600px;height:300px;" ' \
                               'onclick="window.open(this.src)" align="right" /></div>'.format(screenshot_base64)
                # 将包含屏幕截图的 HTML 标签添加到测试报告的 extra 属性中。
                extra.append(pytest_html.extras.html(html_content))
        # 更新测试报告的 extra 属性。
        report.extra = extra
    # 将测试函数的 docstring(函数说明)作为测试报告的描述。
    report.description = str(item.function.__doc__)

def _capture_screenshot():
    """
    截图保存为base64编码的字符串
    """
    if driver is not None:
        return driver.get_screenshot_as_png()
    return None

@pytest.fixture(scope='session', autouse=True)
def browser(request):
    global driver
    if driver is None:
        driver = webdriver.Chrome()
        driver.implicitly_wait(10)
        driver.maximize_window()
    def end():
        driver.quit()

    request.addfinalizer(end)
    return driver

钩子函数说明:

@pytest.mark.hookwrapper 是 Pytest 测试框架中的一个装饰器,用于定义测试钩子函数的包装器。

在 Pytest 中,测试钩子函数是在执行测试过程中的特定事件点被触发的函数。通过使用 @pytest.mark.hookwrapper 装饰器,可以对测试钩子函数进行包装,并在包装器中添加额外的逻辑。这使得我们可以在测试钩子的前后执行自定义代码。

具体而言,@pytest.mark.hookwrapper 可以在以下事件点触发钩子函数的执行:

  • pytest_runtest_protocol:在运行每个测试用例之前和之后。
  • pytest_collection_modifyitems:在收集测试用例之前和之后。

使用 @pytest.mark.hookwrapper 装饰器定义的包装器函数需要满足以下条件:

  • 函数必须是一个生成器函数(使用 yield 语句)。
  • 函数要负责执行钩子函数以及处理额外的逻辑。
  • 通过 yield 语句将控制权转移给原始的钩子函数。
  • 可以在 yield 语句之前和之后执行自定义代码。

通过使用 @pytest.mark.hookwrapper 装饰器,可以方便地修改和扩展 Pytest 的行为,以适应特定的测试需求。

1.3.2.创建test_html_screenshot.py文件

在test_case包下创建test_html_screenshot.py,代码如下,进行测试:

from selenium import webdriver
import time

def test_case01(browser):
    """
    测试用例1 失败用例
    """
    browser.get("https://www.baidu.com/")
    time.sleep(2)
    t = browser.title
    assert t == "酒剑仙"

def test_case02(browser):
    """
    测试用例2 成功用例
    """
    browser.get("https://www.baidu.com/")
    time.sleep(2)
    t = browser.title
    assert t == "百度一下,你就知道"

1.3.3.测试

通过下面命令执行如下:

pytest .\test_case\test_html_screenshot.py --html=report.html --self-contained-html

执行后如下:

Python生成html报告集成错误截图、重复执行用例、用例执行顺序、多重断言_用例

二、Pytest-repeat(重复执行用例) 

pytest-repeat 是一个 Pytest 的插件,它的作用是允许你在运行测试用例时进行重复运行。

有时候,在某些特殊的情况下,你可能希望重复运行一组测试用例多次以验证其稳定性或进行性能测试。这时,pytest-repeat 可以提供便利的方法来实现这个目的。

2.1.安装

在命令行中运行以下命令进行安装:

pip install pytest-repeat

或者(使用国内的豆瓣源,数据会定期同步国外官网,速度快。)

pip install pytest-repeat -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com

2.2.操作参数

重复执行用例的时候,有两种方式,分别是通过命令行参数和通过装饰器

2.2.1.命令行参数:

--count=n(运行n次一个或多个测试用例)

参数说明:

--count n

--repeat-scope(可以覆盖默认的测试用例执行顺序,类似 fixture 的 scope 参数)

  • function:默认值,范围针对每个用例重复执行,再执行下一个用例。
  • class:以类为用例集合单位,重复执行类里面的用例,再执行下一个。
  • module:以模块为单位,重复执行模块里面的用例,再执行下一个。
  • session:重复整个测试会话,即所有测试用例执行一次,然后再次执行所有此类测试。

-x(如果您尝试诊断间歇性故障,则一次又一次地运行相同的测试直到失败。可以将 pytest 的 -x 选项与 pytest-repeat 结合使用,以强制测试运行器在第一次失败时停止

pytest --count=5 -x test_case01.py

这将尝试运行test_case01.py 5次,但将在发生故障后立即停止。

2.2.1.装饰器参数

如果要在代码中将某些测试用例标记为执行重复多次,可以使用此装饰器,

@pytest.mark.repeat(count)

案例

import pytest

@pytest.mark.repeat(5)
def test_example():
    assert 2 + 2 == 4

2.3.兼容性 

pytest-repeat 不能与 unittest.TestCase 测试类一起使用。无论 --count 设置多少,这些测试始终仅运行一次,并显示警告。 

三、pytest-ordering(用例执行顺序)

pytest-ordering 插件可以控制用例的执行顺序。

3.1.安装

在命令行中运行以下命令进行安装:

pip install pytest-ordering

或者(使用国内的豆瓣源,数据会定期同步国外官网,速度快。)

pip install pytest-ordering -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com

3.2.pytest默认执行

创建test_ordering.py文件,pytest默认的执行顺序(用例先后顺序执行)

def test_case2():
    print("用例test_case2")
    assert True

def test_case1():
    print("用例test_case1")
    assert True

def test_case3():
    print("用例test_case3")
    assert True

执行用例,命令如下:

pytest .\test_case\test_ordering.py -sv

执行后如下:

Python生成html报告集成错误截图、重复执行用例、用例执行顺序、多重断言_用例_02

3.3、pytest-ordering自定义用例顺序 

修改test_ordering.py文件,通过@pytest.mark.run(order=2)注解定义用例执行顺序,代码如下:

import pytest

@pytest.mark.run(order=2)
def test_case2():
    print("用例test_case2")
    assert True

@pytest.mark.run(order=3)
def test_case1():
    print("用例test_case1")
    assert True

@pytest.mark.run(order=1)
def test_case3():
    print("用例test_case3")
    assert True

打开命令行,在该脚本目录下,输入执行命令

Python生成html报告集成错误截图、重复执行用例、用例执行顺序、多重断言_html_03

四、pytest-assume(多重断言)

pytest 中可以用 python 的 assert 断言,也可以写多个断言,但是如果一个失败,那么后面的断言将不再执行。此时可以用 pytest-assume 插件,每个测试允许多次失败。

4.1.安装

在命令行中运行以下命令进行安装:

pip install pytest-assume

或者(使用国内的豆瓣源,数据会定期同步国外官网,速度快。)

pip install pytest-assume -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com

4.2.assert多重断言

创建test_assert.py文件,代码如下:

def test_addcase():
    assert 1 + 2 == 3
    assert 1 + 3 == 4
    assert 1 + 4 == 6
    assert 1 + 5 == 6
    print("测试完成")

运行结果,第三个断言(assert 1 + 4 == 6)失败之后,后面的断言也不会执行,包括正常的代码:

Python生成html报告集成错误截图、重复执行用例、用例执行顺序、多重断言_html_04

4.3.pytest-assume多重断言 

创建test_assume.py文件,代码如下:

import pytest

def test_addcase():
    pytest.assume(1 + 2 == 3)
    pytest.assume(1 + 3 == 4)
    pytest.assume(1 + 4 == 6)
    pytest.assume(1 + 5 == 6)
    print("测试完成")

运行结果,第三个断言(pytest.assume(1 + 4 == 6))失败之后,后面的断言还是会执行的。

Python生成html报告集成错误截图、重复执行用例、用例执行顺序、多重断言_html_05

4.4.上下文管理器 

pytest.assume 可以用作围绕普通断言的上下文管理器。它可以帮助我们在测试中收集多个断言的结果,并在最后一起报告。创建 test_assume02.py代码如下:

import pytest

def test_example():
    values = [1, 2, 3, 4, 5]
    with pytest.assume:
        # 第一个断言
        assert len(values) == 5

    with pytest.assume:
        # 第二个断言
        assert sum(values) == 15

    with pytest.assume:
        # 第三个断言
        assert values[2] == 3

注意:

  • 在上面的案例中,使用 pytest.assume 创建了一个上下文管理器,并在每个 with pytest.assume: 代码块中放置了一个断言。每个断言都会在测试期间执行,并且即使某个断言失败,后续的断言也会被执行。
  • 当我们运行这个测试用例时,Pytest 将会报告每个断言的结果,而不会在第一个断言失败后停止执行其他断言的验证。这样我们就可以收集多个断言的结果,并一起查看测试报告。
  • 这种方式尤其适用于测试中的多个断言场景,它可以在一次运行中捕获所有断言的结果,提供更全面的测试报告。
  • 每个 with 块只能有一个断言。如果有多个断言,当第一个失败了,则不会完全验证之后的所有断言



【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月18日 0

暂无评论

推荐阅读
  wURKzOHw9Irf   2023年12月24日   30   0   0 HTMLicoicohtml
  8l4CZpTOKa7P   2023年12月26日   40   0   0 htmlhtml
  dwHry2iKGG0I   2023年12月26日   31   0   0 githubgithubhtmlhtml
VxbKCNpUI3P6