pytest - 参数化

参数化:单个参数


# 参数化:单个参数
语法:`@pytest.mark.parametrize(参数变量,['数值1', '数值2',...])`
demo:
```python
"""
pytest 参数化演示:单个值
"""
import pytest


class TestDemo(object):

    @pytest.mark.parametrize('name', ['张飞', '关羽', '刘备'])
    def test_demo01(self, name):
        print("my name is %s " % name)


if __name__ == '__main__':
    pytest.main(['-s', '07_pytest_parameterized.py'])

结果:

============================= test session starts =============================
collecting ... collected 3 items

07_pytest_parameterized.py::TestDemo::test_demo01[\u5f20\u98de] my name is 张飞 
PASSED
07_pytest_parameterized.py::TestDemo::test_demo01[\u5173\u7fbd] my name is 关羽 
PASSED
07_pytest_parameterized.py::TestDemo::test_demo01[\u5218\u5907] my name is 刘备 
PASSED

============================== 3 passed in 0.01s ==============================

参数化:多个参数

语法:@pytest.mark.parametrize('参数1,参数2,...', [(), (),(),])
demo:

"""
pytest 参数化:多个参数演示
"""
import pytest


class TestDemo(object):

    # 注意:
    # 1.name 和 age 是在一个字符串中
    # 2.参数值的格式必须是[(), (), ()]
    @pytest.mark.parametrize('name, age', [('刘备', 35), ('张飞', 25), ('关羽', 29)])
    def test_method(self, name, age):
        print("my name is %s , I'm %d year old" % (name, age))


if __name__ == '__main__':
    pytest.main(['-s', '08_pytest_parameterize.py'])

结果:

============================= test session starts =============================
collecting ... collected 3 items

08_pytest_parameterize.py::TestDemo::test_method[\u5218\u5907-35] my name is 刘备 , I'm 35 year old
PASSED
08_pytest_parameterize.py::TestDemo::test_method[\u5f20\u98de-25] my name is 张飞 , I'm 25 year old
PASSED
08_pytest_parameterize.py::TestDemo::test_method[\u5173\u7fbd-29] my name is 关羽 , I'm 29 year old
PASSED

============================== 3 passed in 0.01s ==============================

多个参数化

一个测试用例可以标记多个@pytest.mark.parametrize

import pytest

@pytest.mark.parametrize('test_input',[1,2,3])
@pytest.mark.parametrize('test_output,expect', [(4,5),(6,7)])
def test_multi(test_input, test_output, expect):
    pass

out:

PS E:\PyProject\pytestDemo> pytest -rA -s
======================================================================= test session starts =======================================================================
platform win32 -- Python 3.10.1, pytest-7.2.0, pluggy-1.0.0
rootdir: E:\PyProject\pytestDemo
collected 6 items                                                                                                                                                   

test_scripts\test_importtoskip.py ......

============================================================================= PASSES ============================================================================== 
===================================================================== short test summary info ===================================================================== 
PASSED test_scripts/test_importtoskip.py::test_multi[4-5-1]
PASSED test_scripts/test_importtoskip.py::test_multi[4-5-2]
PASSED test_scripts/test_importtoskip.py::test_multi[4-5-3]
PASSED test_scripts/test_importtoskip.py::test_multi[6-7-1]
PASSED test_scripts/test_importtoskip.py::test_multi[6-7-2]
PASSED test_scripts/test_importtoskip.py::test_multi[6-7-3]
======================================================================== 6 passed in 0.01s ======================================================================== 

实际收集到的用例是它们所有可能的组合

pytestmark 实现参数化

可以尝试通过对pytestmark复制,参数化一个测试模块

import pytest

# pytestmark: 固定写法,不是pytestmark 会报错
pytestmark = pytest.mark.parametrize('test_input,expect', [(1,2),(3,4)])

def test_one(test_input,expect):
    assert  test_input + 1 == expect

out:

PS E:\PyProject\pytestDemo> pytest -sv
======================================================================= test session starts =======================================================================
platform win32 -- Python 3.10.1, pytest-7.2.0, pluggy-1.0.0 -- e:\pyproject\pytestdemo\venv\scripts\python.exe
cachedir: .pytest_cache
rootdir: E:\PyProject\pytestDemo
collected 2 items                                                                                                                                                   

test_scripts/test_importtoskip.py::test_one[1-2] PASSED
test_scripts/test_importtoskip.py::test_one[3-4] PASSED

======================================================================== 2 passed in 0.01s ========================================================================

需要注意的是,该模块内的所有方法的入参都需要与parametrize声明的变量保持一致

argnames 参数

parametrize 方法中的第一个参数argnames 是一个用逗号分隔的字符串,或者一个元组/列表,表明指定的参数名。argnames 通常是与被标记测试方法入参的参数名
对应的,但实际上有一些限制,只能是被标记测试方法入参的子集

"""
# 源码注释:
        :arg argnames: a comma-separated string denoting one or more argument
                       names, or a list/tuple of argument strings.
"""

argnames 覆盖同名的fixture

通常在使用fixture 和参数parametrize时,可以一个参数使用参数化,另一个参数使用fixture和参数化,而同时使用fixture和parametrize时,
parametrize 的值会覆盖原来的fixture返回的值

import pytest


@pytest.fixture()
def expected():
    return 2


@pytest.fixture()
def input():
    return 0


@pytest.mark.parametrize('input', [1])  # 实际取的是parametrize中的1,fixture - input 被覆盖掉
def test_sample(input, expected):
    assert input + 1 == expected

执行结果:

argvalues 参数

  • 参数化中参数值argvalues 是一个可迭代对象
  • 如果argnams 包含多个参数,那么argvalus的迭代返回元素必须是可度量的值,即支持len()方法,并且长度和argnames所声明参数的个数相等,
    所以它可以是元组/列表/集合等。

argvalues 值的来源可以是以下场景:

  • Excel表中
  • csv文件中
  • 数据库中
"""
        :arg argvalues: The list of argvalues determines how often a
            test is invoked with different argument values.  If only one
            argname was specified argvalues is a list of values.  If N
            argnames were specified, argvalues must be a list of N-tuples,
            where each tuple-element specifies a value for its respective
            argname.
"""

使用pytest.param 为argvalues赋值

import pytest

@pytest.mark.parametrize('input, expect', [(4, 2), pytest.param(6, 3, marks=pytest.mark.xfail, id='XPASS')])
def test_sample(input, expect):
    assert input / 2 == expect

运行结果:

无论argvalues 中传递的是可度量的对象还是具体的值,在源码中都会封装成一个ParameterSet对象,它是一个具名元组:`

直接使用ParameterSet看看效果如何?

import pytest

from _pytest.mark.structures import ParameterSet


@pytest.mark.parametrize('input, expect', [(4, 2), ParameterSet(values=[6,3],marks=[pytest.mark.xfail],id='XPASS')])
def test_sample(input, expect):
    assert input / 2 == expect

运行结果:

成功运行,因此可以总结 pytest.param 的作用就是封装一个ParameterSet

posted @   chuangzhou  阅读(189)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示