pytest中参数化方法,并且根据执行的命令进行动态参数化

@pytest.mark.parametrize

pytest.mark.parametrize可以实现参数化,它包含的参数有:

  • argnames:一个或者多各参数名,逗号分割
  • argvalues:和argnames对应,若argname只有一个值列表,那么argvalues也只有一个值,如果有n个argname,argvalues必须时n元组的列表
  • indirect:它的值是bool值或者argnames的子集;如果是True,则表示argnames中的所有名称,通过argname对应的fixture函数传递进行赋值,而不是在进行用例收集时就赋值
  • ids:每组参数的id
  • scope:指定参数范围

元组组成的列表进行参数化,每一组元素表示一组参数化值

  • 如下使用testdata值进行参数化
#content of test_param.py
#coding=utf-8
import pytest

testdata = [
    (3, 4, -1),
    (6,3, 3),
]

@pytest.mark.parametrize("a,b,expected", testdata)
def test_diff_v0(a, b, expected):
    diff = a - b
    assert diff == expected
  • 执行pytest test_param.py --collect-only查看收集的用例如下:
    收集到两个用例test_diff_v0[3-4--1]test_diff_v0[6-3-3]
D:\Python\program\practic_unittest>pytest test_param.py --collect-only
============================================================================ test session starts =============================================================================
platform win32 -- Python 3.8.4, pytest-6.2.4, py-1.9.0, pluggy-0.13.1
rootdir: D:\Python\program\practic_unittest, configfile: pytest.ini
plugins: allure-pytest-2.8.16
collected 2 items                                                                                                                                                             

<Module test_param.py>
  <Function test_diff_v0[3-4--1]>
  <Function test_diff_v0[6-3-3]>

========================================================================= 2 tests collected in 0.02s =========================================================================

每个参数单独赋值

  • 根据每个元素值的个数,每个参数值组合生成一条用例
#content of test_param.py
#coding=utf-8
import pytest

testdata = [
    (3, 4),
    (6,3),
]
@pytest.mark.parametrize("expected", [-1,3])
@pytest.mark.parametrize("a,b", testdata)
def test_diff_v1(a, b, expected):
    diff = a - b
    assert diff == expected
  • 执行pytest test_param.py --collect-only查看收集的用例如下:
    收集到四(2*2)个用例test_diff_v1[3-4--1]test_diff_v1[3-4-3]test_diff_v1[6-3--1]test_diff_v1[6-3-3]
D:\Python\program\practic_unittest>pytest test_param.py --collect-only
============================================================================ test session starts =============================================================================
platform win32 -- Python 3.8.4, pytest-6.2.4, py-1.9.0, pluggy-0.13.1
rootdir: D:\Python\program\practic_unittest, configfile: pytest.ini
plugins: allure-pytest-2.8.16
collected 4 items                                                                                                                                                             

<Module test_param.py>
  <Function test_diff_v1[3-4--1]>
  <Function test_diff_v1[3-4-3]>
  <Function test_diff_v1[6-3--1]>
  <Function test_diff_v1[6-3-3]>

========================================================================= 4 tests collected in 0.02s ========================================================================

添加用例id

  • 通过以上的例子可以看出生成的用例名称后面跟的是参数的值,可以通过各ids或者id赋值,指定用例标识
#content of test_param.py
# coding=utf-8
import pytest

testdata = [
    (3, 4, -1),
    (6, 3, 3),
]


@pytest.mark.parametrize("a,b,expected", testdata, ids=["test1", "test2"])
def test_diff_v2(a, b, expected):
    diff = a - b
    assert diff == expected
  • 执行pytest test_param.py --collect-only查看收集的用例如下:
    收集到两个用例test_diff_v2[test1]test_diff_v2[test2]
D:\Python\program\practic_unittest>pytest test_param.py --collect-only
============================================================================ test session starts =============================================================================
platform win32 -- Python 3.8.4, pytest-6.2.4, py-1.9.0, pluggy-0.13.1
rootdir: D:\Python\program\practic_unittest, configfile: pytest.ini
plugins: allure-pytest-2.8.16
collected 2 items                                                                                                                                                             

<Module test_param.py>
  <Function test_diff_v2[test1]>
  <Function test_diff_v2[test2]>

========================================================================= 2 tests collected in 0.02s =========================================================================

pytest.param, 针对单个参数化添加mark标记或者id

  • 对于添加了mark标记的,可通过-m name来执行指定用例
  • pytest.param的参数有:
    values:参数值
    marks: 参数添加mark标记,可以是单个值也可以是一个列表
    id:设置参数的id
#content of test_param.py
# coding=utf-8
import pytest

#利用pytest.param添加
@pytest.mark.parametrize("a,b,expected",
    [(4,2,1), pytest.param(9,3,6, marks=pytest.mark.xfail,id="expect fail")
     ,pytest.param(5,3,1,marks=[pytest.mark.first,pytest.mark.xfail],id="test3")],
)
def test_diff_v3(a, b, expected):
    diff = a - b
    assert diff == expected

#content of pytest.ini
[pytest]
markers=first:mark run first
  • 执行pytest test_param.py --collect-only查看收集的用例如下:
    收集到三个用例,但是只选择了有xfail标记的test_diff_v3[expect fail]test_diff_v3[test3]
D:\Python\program\practic_unittest>pytest test_param.py --collect-only -m xfail
============================================================================ test session starts =============================================================================
platform win32 -- Python 3.8.4, pytest-6.2.4, py-1.9.0, pluggy-0.13.1
rootdir: D:\Python\program\practic_unittest, configfile: pytest.ini
plugins: allure-pytest-2.8.16
collected 3 items / 1 deselected / 2 selected                                                                                                                                 

<Module test_param.py>
  <Function test_diff_v3[expect fail]>
  <Function test_diff_v3[test3]>

================================================================ 2/3 tests collected (1 deselected) in 0.02s =================================================================

利用indirect参数,通过fixture实现间接参数化

# content of test_param.py
# coding=utf-8
import pytest

@pytest.fixture(scope="function")
def x(request):
    return request.param * 3

@pytest.fixture(scope="function")
def y(request):
    return request.param * 2


@pytest.mark.parametrize("x, y", [("a", "b")], indirect=True)
def test_indirect(x, y):
    assert x == "aaa"
    assert y == "bb"
  • 执行pytest test_param.py用例执行通过
D:\Python\program\practic_unittest>pytest test_param.py
============================================================================ test session starts =============================================================================
platform win32 -- Python 3.8.4, pytest-6.2.4, py-1.9.0, pluggy-0.13.1
rootdir: D:\Python\program\practic_unittest, configfile: pytest.ini
plugins: allure-pytest-2.8.16
collected 1 item                                                                                                                                                              

test_param.py::test_indirect[a-b] PASSED                                                                                                                                [100%]

============================================================================= 1 passed in 0.02s ==============================================================================
  • 修改test_param.py中的@pytest.mark.parametrize("x, y", [("a", "b")], indirect=True)@pytest.mark.parametrize("x, y", [("a", "b")], indirect=["x"])后,执行结果是不通过,因为在断言assert y == "bb"时不通过
D:\Python\program\practic_unittest>pytest test_param.py
============================================================================ test session starts =============================================================================
platform win32 -- Python 3.8.4, pytest-6.2.4, py-1.9.0, pluggy-0.13.1
rootdir: D:\Python\program\practic_unittest, configfile: pytest.ini
plugins: allure-pytest-2.8.16
collected 1 item                                                                                                                                                              

test_param.py::test_indirect[a-b] FAILED                                                                                                                                [100%]

================================================================================== FAILURES ==================================================================================
_____________________________________________________________________________ test_indirect[a-b] _____________________________________________________________________________

x = 'aaa', y = 'b'

    @pytest.mark.parametrize("x, y", [("a", "b")], indirect=["x"])
    def test_indirect(x, y):
        assert x == "aaa"
>       assert y == "bb"
E       AssertionError: assert 'b' == 'bb'
E         - bb
E         + b

test_param.py:16: AssertionError
========================================================================== short test summary info ===========================================================================
FAILED test_param.py::test_indirect[a-b] - AssertionError: assert 'b' == 'bb'
============================================================================= 1 failed in 0.13s ==============================================================================

pytest_generate_tests

  • 利用pytest_generate_tests钩子可以动态确定参数或者fixture范围,通过传入的metafunc对象可以检查请求上下文,调用metafunc.parametrize()进行参数化
  • metafunc.parametrize()的参数值和pytest.mark.parametrize一样

根据输入命令动态选择参数值

比如需要在多个环境运行脚本,而每个环境的参数不一样,可通过一下方式来实现动态赋值
在conftest.py中定义

# content of test_param.py
# coding=utf-8
import pytest

def test_compute(param):
    assert param < 4

#conftest.py
def pytest_addoption(parser):
    parser.addoption("--dev", action="store_true", help="run in dev env,otherwise run in test env")   #带--dev参数时默认值时true,不带时为false
# action的值store、store_const,store_true,store_false,append,append_const,count,extend

def pytest_generate_tests(metafunc):
    if "param" in metafunc.fixturenames:
        if metafunc.config.getoption("dev"):
            name = [1,2,3]
        else:
            name = [3,4,5]
        metafunc.parametrize("param", name)
  • 执行pytest test_param.py --collect-only和执行pytest test_param.py --collect-only --dev查看收集的用例如下:
    分别取name=[3,4,5]name=[1,2,3]的值
D:\Python\program\practic_unittest>pytest test_param.py --collect-only
============================================================================ test session starts =============================================================================
platform win32 -- Python 3.8.4, pytest-6.2.4, py-1.9.0, pluggy-0.13.1
rootdir: D:\Python\program\practic_unittest, configfile: pytest.ini
plugins: allure-pytest-2.8.16
collected 3 items                                                                                                                                                             

<Module test_param.py>
 <Function test_compute[3]>
 <Function test_compute[4]>
 <Function test_compute[5]>

========================================================================= 3 tests collected in 0.02s =========================================================================

D:\Python\program\practic_unittest>pytest test_param.py --collect-only --dev
============================================================================ test session starts =============================================================================
platform win32 -- Python 3.8.4, pytest-6.2.4, py-1.9.0, pluggy-0.13.1
rootdir: D:\Python\program\practic_unittest, configfile: pytest.ini
plugins: allure-pytest-2.8.16
collected 3 items                                                                                                                                                             

<Module test_param.py>
 <Function test_compute[1]>
 <Function test_compute[2]>
 <Function test_compute[3]>

========================================================================= 3 tests collected in 0.02s =========================================================================

执行命令动态输入参数值

如下代码parser.addoption的action改为append后(更多action值地址),在执行命令时把输入的值传给参数

# content of test_param.py
# coding=utf-8
import pytest

def test_compute(param):
   assert param < 4

#conftest.py
def pytest_addoption(parser):
   parser.addoption("--dev", action="apend", help="run in dev env,otherwise run in test env")   #带--dev参数时默认值时true,不带时为false
#action的值store、store_const,store_true,store_false,append,append_const,count,extend

def pytest_generate_tests(metafunc):
   if "param" in metafunc.fixturenames:
       metafunc.parametrize("param",metafunc.config.getoption("dev"))  #metafunc.config.getoption检索命令行选项的值,取到的dev值赋给param参数,metafunc.config.getini(name) 检索 ini 样式文件中读取的值
  • 执行pytest test_param.py --collect-only --dev 3或者pytest test_param.py --collect-only --dev 3 --dev 45分别收集到一条/两条用例:
    test_compute[3]test_compute[45]
D:\Python\program\practic_unittest>pytest test_param.py --collect-only --dev 3
============================================================================ test session starts =============================================================================
platform win32 -- Python 3.8.4, pytest-6.2.4, py-1.9.0, pluggy-0.13.1
rootdir: D:\Python\program\practic_unittest, configfile: pytest.ini
plugins: allure-pytest-2.8.16
collected 1 item                                                                                                                                                              

<Module test_param.py>
 <Function test_compute[3]>

========================================================================= 1 test collected in 0.02s ==========================================================================

D:\Python\program\practic_unittest>pytest test_param.py --collect-only --dev 3 --dev 45
============================================================================ test session starts =============================================================================
platform win32 -- Python 3.8.4, pytest-6.2.4, py-1.9.0, pluggy-0.13.1
rootdir: D:\Python\program\practic_unittest, configfile: pytest.ini
plugins: allure-pytest-2.8.16
collected 2 items                                                                                                                                                             

<Module test_param.py>
 <Function test_compute[3]>
 <Function test_compute[45]>

========================================================================= 2 tests collected in 0.03s =========================================================================

参考文档:https://docs.pytest.org/en/6.2.x/example/parametrize.html#paramexamples

猜你喜欢

转载自blog.csdn.net/z917185537/article/details/118899617
今日推荐