Pytest接口自动化基础知识

一、Pytest简介及与Unittest区别

1、Pytest简介

Pytest是一个流行的Python测试框架。它支持各种类型的测试,如单元测试、集成测试和功能测试。 Pytest具有易于阅读的语法和丰富的插件生态系统,可以轻松管理测试套件,生成报告,运行测试并与其他测试框架和工具集成。 Pytest的主要优点包括:

  • 易于学习和使用:Pytest具有简单的API和易于阅读的语法,使得编写测试用例变得简单容易。
  • 丰富的插件生态系统:Pytest具有庞大的插件生态系统,使得扩展和自定义测试功能变得容易。
  • 灵活性:Pytest可以很容易地集成到现有的测试基础设施中,并可根据需要定制测试套件。
  • 大量的文档和社区支持:Pytest有大量的文档和社区支持,可以帮助您快速解决问题和学习新的技能。

总之,Pytest是一款强大,易用且灵活的测试框架,旨在提高Python代码的质量和可靠性。

2、Pytest与Unittest区别

Pytest和Unittest都是Python中常用的测试框架,它们的主要区别如下:

  1. 编写测试用例的方式不同:Unittest使用类和方法,需要继承unittest.TestCase类,并且使用一系列assert方法进行断言;而Pytest则使用函数进行测试,不需要继承任何类。

  2. 测试用例的组织方式也不同:Unittest需要在测试文件中定义测试方法,并使用unittest.main()函数来执行测试;而Pytest则更加灵活,按照文件名或标记来组织测试用例。

  3. 断言方式不同:Unittest有一系列assert方法,如assertEqual、assertTrue、assertFalse等,需要使用这些方法进行断言;而Pytest也有一些内置的assertion方法,但它还提供了一些其他的插件,如pytest-asserts、pytest-bdd等,可以扩展其断言功能。

  4. 报告方式不同:Unittest的测试报告比较简单,只能输出到控制台或文本文件中;而Pytest的测试报告可以生成各种格式,如HTML、XML、JUnit等。

总的来说,Pytest相对于Unittest来说,更加简洁、灵活,并且可扩展性更强。但是在某些场景下,如需要与其他测试框架进行集成,或者需要使用更多的断言方法,Unittest可能会更适合一些。但让人惊喜的是Pytest可以兼容Unittest的测试用例。

二、Pytest测试用例的运行规则

pytest测试用例的运行规则如下:

  1. pytest会在当前目录及其子目录中寻找以"test_"或"Test"开头的.py文件里的测试用例,并执行它们。

  2. pytest会执行所有以"test_"开头的函数作为测试用例。

  3. pytest会自动识别并执行unittest.TestCase类中的所有测试方法。

  4. pytest会自动搜索并执行所有名为"test_"或"_test"的函数、方法或类名。

  5. pytest可以通过命令行参数来运行指定的测试用例,例如:pytest test_sample.py::test_function。

  6. pytest可以使用插件来扩展其测试用例的执行行为,例如:pytest-html可以生成测试报告。

总之,pytest非常灵活,可以根据特定的需求自定义测试用例的执行规则,这也是为什么pytest成为了Python中最流行的测试框架之一的原因之一。

1、pytest运行的几种方式

pytest可以通过以下方式运行:

1.1.通过命令行运行pytest

在命令行中输入以下命令:

pytest [options] [file_or_dir] [file_or_dir] [...]

其中,[options]是pytest的选项,[file_or_dir]是要测试的文件或目录(可以是相对或绝对路径),[file_or_dir] [...]表示可以一次测试多个文件或目录。

例如,要测试当前目录下的所有测试文件,可以在命令行中输入以下命令:

pytest .

1.2.通过测试脚本运行pytest

可以将测试脚本中的代码设置为调用pytest。例如,可以创建一个名为test_all.py的Python脚本,其中包含以下代码:

import pytest

pytest.main(['-x', '-v'])

其中,-x选项表示在遇到第一个失败时停止测试,-v选项表示显示详细的测试结果。

然后在命令行中运行以下命令:

pytest test_all.py

pytest将运行test_all.py中的代码,并执行所有测试。

1.3. 通过集成开发环境运行pytest

如果您使用的是支持pytest的集成开发环境(如PyCharm),可以通过点击运行按钮或快捷键来运行pytest。具体操作可以查看相关IDE的文档。

无论使用哪种方式,pytest都能够快速、高效地运行测试用例,并输出详细的测试结果报告。

三、Pytest装饰器

1、@pytest.fixture:用于定义fixture,这是pytest的一个关键概念,它可以在多个测试用例中共享资源或者数据。还可以实现自动化测试中的setup和teardown工作。

下面举几个fixture使用的例子:

1.1. 用fixture实现setup和teardown工作
#conftest.py
import pytest

@pytest.fixture(scope="session",autouse=True)
def setup():
    print("\n打开浏览器")
    yield
    print("\n关闭浏览器")

#test.py
def test_example01():
    print("\nrunning test1")

def test_example02():
    print("\nrunning test2")

        执行结果如下,其实可以发现通过yield可以在一个函数里实现setup和teardown,yield之前的操作会在执行测试用例之前执行,yield之后的操作会在测试用例全部执行完后子再执行。

同时我们可以发现fixture装饰器是用到了scope、autouse这些参数,下面我们具体讲一些fixture自带的参数及使用方式。

1.2. @pytest.fixture参数scope

是的,pytest.fixture自带参数scope,可以用来控制fixture的作用域。

scope参数有4个可选值:

  • function:fixture将在每个测试函数被调用时执行,默认值。
  • class:fixture将在每个测试类中的所有测试方法开始前执行。
  • module:fixture将在每个模块中所有测试函数被调用前执行。
  • session:fixture将在整个测试过程中执行一次,不管有多少个测试模块和类
1.3.fixture函数使用的3种方式

下面这段代码里用到了fixture函数的3种使用方式:

#conftest.py
import pytest

@pytest.fixture(scope="session",autouse=True)
def setup():
    print("\n打开浏览器")
    yield
    print("\n关闭浏览器")

#test.py
@pytest.mark.usefixtures("setup")
def test_example01():
    print("\nrunning test1")

def test_example02(setup):
    print("\nrunning test2")

1. 使用fixture自带的参数autouse

2. 使用装饰器@pytest.mark.usefixtures()修饰需要运行的用例

3. 测试用例中直接调用fixture函数

例子中用到了3种方式来执行fixture,那fixture函数是不是执行了3次呢?其实并不是的。

通过下面的执行结果可知fixture函数里的打开、关闭浏览器都只执行了一次,说明fixture在它的scope范围内无论调用几次,都只会执行一次。

1.4.@pytest.fixture参数autouse

autouse默认值是False,不会主动调用fixture函数,只能被其他函数调用;

autouse赋值为True时,fixture函数会自动执行,无需调用,但是如果后面的函数中需要使用fixture中的返回值时,仍需调用。

下面举几个例子来详细说明一下:

fixture函数传参autouse=True,测试用例中不再调用fixture函数

#conftest.py
import pytest

@pytest.fixture(scope="session",autouse=True)
def setup():
    print("\n打开浏览器")
    yield
    print("\n关闭浏览器")

#test.py
def test_example01():
    print("\nrunning test1")

def test_example02():
    print("\nrunning test2")

 运行结果如下,fixture函数在测试用例执行前会自动执行

fixture函数没有传参autouse=True,后面的函数也没有调用fixture函数

#conftest.py
import pytest

@pytest.fixture(scope="session")
def setup():
    print("\n打开浏览器")
    yield
    print("\n关闭浏览器")

#test.py
def test_example01():
    print("\nrunning test1")

def test_example02():
    print("\nrunning test2")

运行结果如下,可以看到fixture函数没有被执行

fixture函数没有传参autouse=True,后面的函数通过@pytest.mark.usefixtures调用fixture函数

#conftest.py
import pytest

@pytest.fixture(scope="session")
def setup():
    print("\n打开浏览器")
    yield
    print("\n关闭浏览器")

#test.py
@pytest.mark.usefixtures("setup")
def test_example01():
    print("\nrunning test1")

def test_example02():
    print("\nrunning test2")

运行结果如下,可以看到fixture函数被执行了

但是@pytest.mark.usefixtures调用fixture函数是取不到fixture里的返回值的,如果要用到fixture里的返回值,就需要用变量接收fixture函数的返回值,举例如下:


import pytest

@pytest.fixture(scope="session")
def setup():
    print("\n打开浏览器")
    yield 123
    print("\n关闭浏览器")


@pytest.mark.usefixtures("setup")
def test_example01():
    print("\nrunning test1")

def test_example02(setup):
    #定义变量result接收setup的返回值
    result = setup
    print("\n打印setup函数的返回值:")
    print(result)
    print("\nrunning test2")

运行结果如下,在测试用例test_example02中使用到了fixture函数的返回值:

 通过上面的例子,我们可以看到test_example01、test_example02使用了两种不同的方式来调用fixture,但是实际执行结果中我们可以看到fixture函数只执行了一次,这就是为什么fixture函数能够用来做统一的事前事后处理操作的原因,因为它可以一次执行,多次引用,不会产生重复的操作。下面举一个更形象的例子:


import pytest

@pytest.fixture(scope="session",autouse=True)
def setup():
    print("\n打开浏览器")
    yield 123
    print("\n关闭浏览器")


def test_example01(setup):
    result = setup
    print("打印test_example01使用的fixture函数的返回值:")
    print(result)
    print("running test1")

def test_example02(setup):
    result = setup
    print("\n打印test_example02使用的fixture函数的返回值:")
    print(result)
    print("running test2")

运行结果如下,可以发现fixture函数中设置autouse=True后,fixture函数在执行test_example01、test_example02前先执行了yield之前的部分,test_example01、test_example02虽然都引用了fixture函数,但是已经执行的操作不会重复执行,只会取fixture中的返回值来使用,带test_example01、test_example02都执行完毕后,才会执行yield之后的操作。

 看了上面的操作,大家可能会感觉到yield好像有跟return一样的功能,但是又好像不一样,下面我们来具体对比一下yield与return。

1.5. @pytest.fixture参数params

 通过pytest.fixture的参数params可以实现多个测试用例间共享测试数据,下面可以看一个例子:


import pytest

test_data = ["username","password"]

@pytest.fixture(scope="session",autouse=True,params=test_data)
def setup(request):
    print("\n打开浏览器")
    print("测试参数:"+request.param)
    yield request.param
    print("\n关闭浏览器")


def test_example01(setup):
    print("running test1:"+setup)

def test_example02(setup):
    print("\nrunning test2:"+setup)

运行结果如下,可是两个测试用例怎么会有4个测试结果呢?原来params中的每一个参数都会执行一次所有的测试用例。

 如果测试用例需要使用多个参数,就需要以元祖的形式来传参


import pytest

test_data = [("username","password")]

@pytest.fixture(scope="session",autouse=True,params=test_data)
def setup(request):
    print("\n打开浏览器")
    yield request.param
    print("\n关闭浏览器")


def test_example01(setup):
    print("running test1:"+setup[0])
    print("running test1:"+setup[1])

def test_example02(setup):
    print("\nrunning test2:"+setup[0])
    print("running test2:" + setup[1])

从测试结果可以看到,元祖内的参数被作为一组参数,在每个测试用例里都用到了。

1.6. yield与return的区别

yield和return都是用于从函数中返回值的关键字,但它们之间有着明显的区别。

  1. yield关键字只能在生成器函数中使用,而return关键字可以在任何函数中使用。

  2. 当函数执行到yield语句时,它会返回一个值并暂时停止执行,等待下一次调用时再次执行,而函数执行到return语句时,它会立即停止执行并返回一个值。

  3. yield语句可以出现多次,每次返回一个值,而return语句只能出现一次。

  4. 使用yield语句可以构建迭代器,可以迭代产生值,而return语句只能返回一个值。

综上所述,yield和return关键字被用于不同的目的,yield语句通常用于构建生成器函数,而return语句用于任何函数中返回一个值并结束函数的执行。

1.7. conftest.py

conftest.py 文件是一个特殊的模块文件,可以用来存放fixture函数、hook函数和插件配置等内容的特殊Python模块。其原理是通过pytest自身的插件机制来实现,具体包括:

  1. 在pytest运行过程中,会自动查找和加载conftest.py模块,并将其中定义的fixture函数、hook函数和插件配置等内容注册到pytest内部的插件系统中。

  2. 在执行测试用例时,pytest会根据测试用例所属的模块、目录等信息来查找和加载符合条件的conftest.py文件,并将其中定义的fixture函数应用到当前测试用例中,从而实现测试用例之间共享fixture函数的目的。

  3. conftest.py文件可以存在于多个文件夹中,pytest在查找和加载conftest.py文件时会按照一定的优先级顺序进行,通常是从当前测试用例所在的目录开始,向上逐级查找,直到找到最高层的conftest.py文件为止。

  4. pytest的插件机制可以实现插件的扩展和定制,用户可以自己编写插件并注册到pytest中,从而实现自定义的功能和行为。

综上所述,pytest的conftest.py机制是通过pytest内部的插件系统来实现的,用户可以自由定义fixture函数、hook函数和插件配置等内容,并通过pytest的机制将其应用到测试用例中。同时,用户也可以编写自己的pytest插件来扩展和定制pytest的行为和功能。

2、@pytest.mark.parametrize:用于参数化测试用例。可以在一个测试函数中多次调用,每次调用使用不同的参数组合执行测试。

2.1. 通过@pytest.mark.parametrize直接给测试用例传参

下面这个例子是通过@pytest.mark.parametrize("参数名",数据) 传参两组值

#test.py
import pytest

@pytest.mark.parametrize("a,b,c",[(1,2,3),(2,3,5)])
def test_example01(a,b,c):
    res = a+b
    assert res==c
2.2. 通过@pytest.mark.parametrize指定测试用例使用fixture的参数

下面这个例子是通过@pytest.mark.parametrize("函数名",测试数据,indirect=True) 给两个测试用例制定了两组不同的测试数据

import pytest

test_data1 = [("username1","password1")]
test_data2 = [("username2","password2")]

@pytest.fixture(scope="session")
def login(request):
    print("\n打开浏览器")
    yield request.param
    print("\n关闭浏览器")

@pytest.mark.parametrize("login",test_data1,indirect = True)
def test_example01(login):
    print(login)

@pytest.mark.parametrize("login",test_data2,indirect = True)
def test_example02(login):
    print(login)

3、@pytest.mark.skip:用于跳过测试用例。

import pytest

def test_example01():
    print("runing test1")

@pytest.mark.skip(reason="跳过测试")
def test_example02():
    print("runing test2")

通过测试结果可以看到,test_example01执行通过,test_example02则SKIPPED

也可以通过判断来选择跳过某些测试用例,pytest.mark.skipif(判断,reason="跳过原因")

import pytest
import sys

def test_example01():
    print("runing test1")

@pytest.mark.skipif(sys.version_info<(3,7),reason="需要python版本在3.7及以上")
def test_example02():
    print("runing test2")

如果使用的python版本是3.7以下,测试用例test_example02 就会被跳过,结果如下:

4、@pytest.mark.xfail:用于标记测试用例预期失败,即使测试用例失败了,也不会引发测试失败。

@pytest.mark.xfail 是 pytest 中一个有用的装饰器,用于标记一些测试用例预期会失败,但是我们仍然希望运行这些测试用例并收集其结果。

一般在以下情况下使用 @pytest.mark.xfail 装饰器:

  • 测试用例预期会失败,但是我们需要运行这些测试用例,以确保不会影响其他的测试用例。
  • 测试用例可能存在 Bug,但是 Bug 确认和修复需要一段时间,为了使测试用例能正常执行,标记为 xfail。

使用方法如下:

import pytest

@pytest.mark.xfail
def test_divide_by_zero():
    assert 1 / 0 == 0

在上面的例子中,我们使用 @pytest.mark.xfail 标记测试用例 test_divide_by_zero 预期会失败,但是我们仍然希望运行这个测试用例并收集其结果。pytest 会运行这个测试用例,但是在测试报告中将其标记为 xfailed,表示它的预期结果是失败的,而且实际也的确失败了。

除了默认情况下标记测试用例为 xfail 外,我们还可以使用其他几种方式来标记测试用例的预期结果。例如:

@pytest.mark.xfail(strict=True, reason='This test is expected to fail.')
def test_divide_by_zero():
    assert 1 / 0 == 0

使用 strict=True 参数标记测试用例为 xfail(strict),表示这个测试用例是有严格要求的,如果实际结果和预期结果不一致,就会抛出 AssertionError。如果不设置 strict=True,则即使实际结果和预期结果不一致,测试用例也不会抛出 AssertionError。

使用 reason 参数可为 xfail 增加一个说明,方便其他人看到这个测试用例时了解预期结果。

除了用装饰器外,还可以直接在用例里通过pytest.xfail的方法标记用例结果为xfail

import pytest

def test_xfail():
    if(1==1 ):
        pytest.xfail("先标记为xfail")

总之, @pytest.mark.xfail 装饰器是 pytest 中一个强大的工具,可以帮助我们在测试过程中应对不同的情况,使测试更加灵活和易于维护。

5、@pytest.mark.timeout:用于设置测试用例的最大执行时间,如果测试用例执行时间超过指定时间,则测试失败。

pytest.mark.timeout 是 pytest 中的一个装饰器,用于测试超时的情况。它允许用户定义测试用例的最大运行时间,并在达到最大运行时间时停止测试用例的运行。

使用示例:

import pytest
import time

@pytest.mark.timeout(5) # 定义测试用例的最大运行时间为5秒
def test_example():
    time.sleep(6) # 测试用例运行时间为6秒,超过最大运行时间

在上面的示例中,测试用例 test_example 的最大运行时间为 5 秒。在测试用例运行时,如果超过了这个时间,pytest 将会抛出 pytest.TimeoutError 异常,停止测试用例运行。

需要注意的是,pytest.mark.timeout 只能应用于固定的测试用例或测试函数,不能应用于参数化的测试用例。如果需要对参数化的测试用例设置超时时间,可以使用 pytest-timeout 插件。

6、@pytest.mark.dependency:

pytest.mark.dependency 可以用来标记测试用例之间的依赖关系。这是在测试用例之间建立依赖关系的一种方式,可以确保测试用例的执行顺序以及解决测试用例之间的依赖关系。

使用pytest.mark.dependency可以按照以下步骤来实现:

标记测试用例之间的依赖关系,例如:

#test.py
import pytest

@pytest.mark.dependency()
def test_a():
    pass

@pytest.mark.dependency(depends=["test_a"])
def test_b():
    pass

其中,test_b 依赖 test_a。

运行测试用例时,使用 --run-xfail 参数来运行被依赖的测试用例,例如:

pytest test.py --run-xfail

这样,当 test_a 失败时,test_b 将被跳过执行,而不是失败。

运行测试用例时,使用 --maxfail 参数来限制测试用例失败的数量,例如:

pytest test.py --maxfail=1

这样,当 test_a 失败时,test_b 将不会运行,测试用例将停止运行。

在测试用例中使用 mark.dependency(name=None, depends=None, scope='function') 来指定测试用例之间的依赖关系,例如:

#test.py
import pytest

@pytest.mark.dependency(name='test_a')
def test_a():
    assert True

@pytest.mark.dependency(name='test_b', depends=['test_a'])
def test_b():
    assert True

@pytest.mark.dependency(name='test_c', depends=['test_b'])
def test_c():
    assert True

这里,test_c 依赖 test_b,test_b 依赖 test_a。

7、@pytest.mark.usefixtures:用于在测试用例中使用fixture。

pytest.mark.usefixtures是pytest的一个fixture用法,它可以让测试函数自动调用指定的fixture函数,而不需要在测试函数中显式调用。具体使用方法在@pytest.fixture那部分有讲到,可以指定每个测试用例使用的fixture

8、@pytest.mark.parametrize_with_cases:用于基于参数生成器和测试用例生成器来参数化测试用例。

这些装饰器可以帮助开发人员控制测试用例的行为和生命周期,从而更好地测试应用程序的各个方面。

四、Pytest支持的第三方插件及使用方式

1、pytest-html:生成漂亮的HTML测试报告

安装pytest-html:pip install pytest-html
pytest-html插件执行命令:pytest --html=report.html

   使用更生成测试报告如下:

2、pytest-xdist:分布式测试

pytest-xdist 是一个 pytest 测试框架的插件,它可以让你在多个 CPU 或者多台机器上并行运行测试用例。这可以大大加快测试用例的执行速度,特别是对于那些本来需要连续运行很长时间的大型测试套件而言,更是如此。

使用 pytest-xdist,你可以使用多种不同的模式来运行测试用例,包括以下几种:

- `--numprocesses`:这种模式会使用多个进程在单台机器上并行地运行测试用例。你可以使用 `--numprocesses` 选项指定要使用的进程数。
- `--dist`:这种模式会使用多台机器来并行运行测试用例。你可以使用 `--dist` 选项指定要使用的机器。
- `--looponfail`:这种模式会在后台持续运行测试用例,仅重新运行前一次运行失败的测试用例。

总体而言,pytest-xdist 是一个提高测试套件运行速度和效率的强大工具。

使用 pytest-xdist 可以按照以下步骤进行:

  1. 安装 pytest-xdist 插件:

    pip install pytest-xdist
    
  2. 运行测试用例时与 xdist 插件进行交互,可以使用以下选项:

    • --numprocesses=n: 这种模式会使用多个进程在单台机器上并行地运行测试用例。你可以使用 `--numprocesses` 选项指定要使用的进程数
    • --dist=loadfile:这种模式会使用多台机器来并行运行测试用例。你可以使用 --dist 选项指定要使用的机器。
    • --looponfail:这种模式会在后台持续运行测试用例,仅重新运行前一次运行失败的测试用例。
    • --verbose:打印进程/机器的信息

    例如,使用以下命令来并行运行测试用例:

    pytest -n=3 --verbose
    

    这将使用三个进程来运行测试用例并输出进程信息。

  3. 如果你希望在多台机器上运行测试用例,则需要做如下准备工作:

    • 配置 SSH 无密码登录,使主机能够访问其他主机

    • 设置远程主机的用户名、密码等信息,放在一个 inventory 文件中

    • 在 pytest.ini 文件中添加如下配置信息:

      [pytest]
      plugins = xdist
      dist = loadfile
      
  4. 使用以下命令在不同的机器上并行运行测试用例:

    pytest -n <num_workers> -v --tx ssh=<username>@<ip_address>//<path/to/virtualenv>
    

    示例中,<num_workers> 表示要使用的进程数量,<username> 表示远程机器的用户名,<ip_address> 表示远程机器的 IP 地址,<path/to/virtualenv> 表示 pyenv 的虚拟环境路径。

总之,使用 pytest-xdist 可以很方便地实现测试用例的并行运行,提高测试效率和速度。

下面有个单机多线程的示例看下分布式执行的效果:

import pytest
import time

def test_example01():
    time.sleep(5)
    print("\nrunning test1")

def test_example02():
    time.sleep(5)
    print("\nrunning test2")

不使用pytest-xdist运行结果如下,总耗时10.07s

使用pytest-xdist,运行pytest -vs test.py -n=2,使用2个线程,耗时5.89s

 如果使用 -n=auto的话,就是自动分配主机的所有CPU数,但是不是线程数越多速度越快的,本是线程的启动就是有性能开销的。

3、pytest-rerunfailures:失败用例重跑

pytest-rerunfailures是pytest的一个插件,它可以自动重新运行失败的测试用例,从而提高测试用例的成功率。

该插件的作用主要是对执行失败的测试用例进行自动重跑,以解决测试过程中由于一些随机因素导致的测试用例失败的情况。当测试用例执行失败时,pytest-rerunfailures会根据指定的重跑次数进行自动重试,如果重试次数仍然失败,则该测试用例会被标记为失败。

使用 pytest-rerunfailures 可以按照以下步骤进行:

  1. 安装 pytest-rerunfailures 插件:

    pip install pytest-rerunfailures
    
  2. 在 pytest.ini 文件中配置 pytest-rerunfailures:

    [pytest]
    reruns = 3
    # 指定重新运行的次数
    
  3. 运行测试用例:

    pytest --reruns=3 test_file.py
    

    这样,当测试用例失败时,pytest-rerunfailures会自动重新运行测试用例,并根据指定的次数进行重跑,直到测试用例执行成功为止。

总之,使用 pytest-rerunfailures 可以有效提高测试用例的成功率,减少测试用例失败的情况,提高测试用例的可靠性。

下面看下示例:

[pytest]
reruns = 3
# 指定重新运行的次数

4、pytest-assume:多重断言

pytest-assume是pytest框架的一个插件,用于在测试过程中添加条件断言,以便更好地理解测试过程中的数据和结果。该插件可以让您在一个测试用例中添加多个断言,在出现第一个失败断言后,它不会停止测试用例的执行,而是继续执行后续的断言,以便更好地了解测试数据和结果的变化。

使用pytest-assume的步骤如下:

  1. 安装pytest-assume插件 pip install pytest-assume
  2. 使用pytest.assume函数来标记断言
import pytest

def test_example01():
    pytest.assume(1==1)
    pytest.assume(1==2)
    pytest.assume(3==3)
    print("\nrunning test1")

在上面的示例中,我们在测试用例中添加了三个断言,并使用pytest.assume函数来标记它们。在出现第一个失败断言后,pytest会继续执行测试用例,以便找到其他可能的问题或数据变化。

运行pytest测试,并使用-v选项查看测试结果,在遇到断言失败的情况下,用例是执行到底的。

pytest-assume插件会在测试过程中自动采集条件断言,并在测试结果中显示每个断言的消息和结果。如果测试用例中的所有断言都成功,则测试结果将显示绿色,否则将显示红色。

优点:pytest-assume插件使测试过程更加灵活和可读性更好,因为它可以在单个测试用例中添加多个断言,而不是在每个测试用例中只添加一个断言。这样可以更轻松有效地理解测试结果。

5、pytest-repeat:重复执行用例

pytest-repeat是一个Pytest插件,可以用于多次运行测试用例以检查其稳定性和一致性。它允许你指定测试用例的重复次数,并在每次运行后输出结果,以帮助你发现问题。

5.1.使用pytest-repeat

需要先安装它:pip install pytest-repeat

可以用装饰器@pytest.mark.repeat(num)来标记用例

@pytest.mark.repeat(3)
def test_example01():
    print("\nrunning test1")

运行结果如下:

当然也可以用命令语句运行测试用例,使用--count参数来指定测试用例的重复次数:

pytest test.py --count=3

这里的--count=3指定了测试用例需要重复执行3次。

注意,pytest-repeat插件会开启多个进程来运行测试用例,因此需要确保测试用例本身是线程安全和可重复执行的。

5.2. 重复执行用例直到失败为止

如果需要验证偶现问题,可以一次又一次地运行相同的测试直到失败,这个插件将很有用

可以将pytest的 -x 选项与pytest-repeat结合使用,以强制测试运行程序在第一次失败时停止

pytest --count=1000 -x test.py

上面的命令意味着会执行用例1000次,如果中间遇到失败的情况就会停止。

5.3. 重复执行的作用域参数--repeat-scope

作用:可以覆盖默认的测试用例执行顺序,类似fixture的scope参数

1、function:默认,范围针对每个用例重复执行,再执行下一个用例

2、 class:以class为用例集合单位,重复执行class里面的用例,再执行下一个

3、module:以模块为单位,重复执行模块里面的用例,再执行下一个

4、session:重复整个测试会话,即所有测试用例的执行一次,然后再执行第二次

pytest --repeat-scope命令可以在指定的作用域内重复运行测试用例。例如,如果你想在函数级别作用域下运行测试用例100次,你可以使用以下命令:

pytest test.py --count=3 --repeat-scope=function

6、pytest-ordering:指定的顺序运行测试用例

pytest-ordering是一个pytest插件,它允许您按照指定的顺序运行测试用例。使用pytest-ordering,您可以将测试用例分成不同的测试组,并指定测试组的顺序。

以下是使用pytest-ordering的步骤:

6.1. 安装pytest-ordering:

pip install pytest-ordering

6.2. 定义测试用例并使用@pytest.mark.run(order=1)装饰器
#test.py

@pytest.mark.run(order=3)
def test_example01():
    print("\nrunning test1")

@pytest.mark.run(order=1)
def test_example02():
    print("\nrunning test2")

@pytest.mark.run(order=2)
def test_example03():
    print("\nrunning test3")

输出如下:

在这个例子中,我们指定了测试用例的顺序,并按照指定的顺序运行了它们。这是一个简单的例子,你可以使用更多的测试用例,并将它们划分成不同的测试组,以便更好地管理和运行它们。

7、allure-pytest

allure-pytest是一个Pytest插件,它可以将测试结果生成一份漂亮的报告并且支持自定义的测试结果展示方式和实时更新。

以下是如何使用pytest-allure插件生成报告的步骤:

7.1. 安装allure-pytest插件和allure:

pip install pytest-allure

allure应用的安装可以参考下面的文章

https://mp.csdn.net/mp_blog/creation/editor/125432436

7.2. allure的使用

在测试用例中,你可以使用allure装饰器标记测试步骤,Allure提供了多个装饰器函数,其中包括以下常用函数:

  • @allure.feature("xxxx"): 标注测试功能模块
  • @allure.story("xxxx"): 标注测试用例模块
  • @allure.issue("xxxx"): 标注用例相关链接
  • @allure.testcase("xxxx"): 标注相关测试用例

例如:

import allure
import pytest

@allure.feature("搜索模块")
class TestSearch():

    @allure.story("搜索")
    @allure.title("测试搜索关键字")
    @allure.issue("https://github.com/qameta/allure-integrations/issues/8")
    @allure.testcase("https://www.baidu.com", "百度搜索")
    @pytest.mark.parametrize("test_input, expected_output", [("allure", "allure"), ("pytest", "pytest"), ("unittest", "unittest")])
    def test_search(self, test_input, expected_output):
        assert test_input == expected_output

 在Pytest命令行参数中添加--alluredir选项来指定生成报告的目录:

pytest --clean-alluredir --alluredir=./allure-results

执行测试用例并自动生成报告:

allure serve allure-results

执行该命令后,将会启动allure服务并自动在浏览器中打开报告页面。

这个例子中,我们使用了@allure.feature、@allure.story、@allure.issue和@allure.testcase装饰器为测试用例添加了丰富的信息。

当执行测试用例后,Allure将会根据装饰器提供的信息自动生成漂亮的测试报告:

8、python批量安装插件

新建一个文件require-install.txt,写入插件name如下

执行命令安装txt文件里的全部插件:pip install -r require-install.txt

#require-install.txt
pytest-html
pytest-xdist
pytest-cov

执行命令安装txt文件里的全部插件:pip install -r require-install.txt

以上是常用的pytest插件及使用方式,当然,还有很多其他的插件可以扩展pytest的功能和灵活性。

五、配置文件pytest.ini的使用

pytest.ini是一个配置文件,可以用于配置pytest测试的行为和选项。它可以位于项目的根目录或者测试文件夹中,并且可以影响整个测试过程。pytest在运行时,首先就会去加载pytest.ini里面的内容,以下是一些pytest.ini的用法:

1、通过设置addopts选项来传递命令行参数:

[pytest]
addopts = -v --cov=my_project --cov-report=html

一些常用的的命令列举如下:

  • –reruns:失败重跑次数
  • –count:重复执行次数
  • -v:显示错误位置以及错误的详细信息
  • -s:等价于pytest--capture=no可以捕获print函数的输出
  • -q:简化输出信息
  • -m:运行指定标签的测试用例
  • -x:一旦错误,则停止运行
  • –maxfail:设置最大失败次数,当超出这个阈值时,则不会在执行测试用例
  • –html=report.html生成测试报告
  • -n=2:设置多线程数,auto代表使用主机CPU数

2、使用markers选项来定义自定义标记:

pytest.ini文件如下:

[pytest]
markers =
    smoke: marks tests as slow (deselect with '-m "not smoke"')
    test: marks tests as fast (deselect with '-m "not test"')

  测试用例如下:

import pytest

@pytest.mark.smoke
def test_example01():
    print("\nrunning test1")

@pytest.mark.test
def test_example02():
    print("\nrunning test2")

运行命令:pytest -m smoke

运行结果如下:

 被标记为smoke的测试用例执行成功,标记为test的测试用例没有执行。如果想选择多个标签的测试用例执行,可以使用下面的命令:pytest -m "smoke or test"

3、使用python_files选项来配置测试文件的匹配模式:

[pytest]
python_files = test_*.py

4、使用norecursedirs选项来排除某些目录:

[pytest]
norecursedirs = .* __pycache__ .git

5、使用timeout选项来设置测试超时时间:

[pytest]
timeout = 5

6、使用cache_dir选项来设置缓存目录:

[pytest]
cache_dir = .pytest_cache

7、使用log_cli选项来启用CLI日志输出:

[pytest]
log_cli = true

以上是一些pytest.ini的基础的使用方法,可以根据自己的需求进行配置。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值