【pytest官方文档】解读-fixtures函数和测试函数的参数化

简介: 【pytest官方文档】解读-fixtures函数和测试函数的参数化

Pytest会在以下几个级别启用测试参数化:


  • pytest.fixture(),可以对fixture函数进行参数化。
  • @pytest.mark.parametrize,可以在测试函数或类中定义多组参数和fixture。
  • pytest_generate_tests,可以自定义参数化方案或扩展。


一、@pytest.mark.parametrize:参数化测试函数


1. 常规用法


对测试函数的参数进行参数化,直接使用内置的装饰器pytest.mark.parameterized即可。


import pytest
@pytest.mark.parametrize("test_input,expected", [("3+5", 8), ("2+4", 6), ("6*9", 42)])
def test_eval(test_input, expected):
    assert eval(test_input) == expected


从代码里可以看出,在装饰器里定义了三个不同的元组。我们把("test_input,expected", [("3+5", 8), ("2+4", 6), ("6*9", 42)])

拆开看:


  • "test_input,expected":这个字符串里定义了2个参数,test_inputexpected
  • ("3+5", 8), ("2+4", 6), ("6*9", 42):这里3个元组,没个元组里有2个元素,依次序分别对应test_inputexpected
  • 3个元组外层的[]:列表里就是参数化具体的传参了,因为里面传了3个不同的元组,所以测试函数test_eval会分别执行3次。


============================= test session starts =============================
platform win32 -- Python 3.9.4, pytest-6.2.3, py-1.10.0, pluggy-0.13.1
rootdir: D:\PycharmProjects\wms-api\interface, configfile: pytest.inicollected 3 items
test_module1.py ..F
demo\test_module1.py:3 (test_eval[6*9-42])
54 != 42
Expected :42
Actual   :54
 <Click to see difference>
test_input = '6*9', expected = 42
    @pytest.mark.parametrize("test_input,expected", [("3+5", 8), ("2+4", 6), ("6*9", 42)])
    def test_eval(test_input, expected):
>       assert eval(test_input) == expected
E       AssertionError: assert 54 == 42
E        +  where 54 = eval('6*9')
test_module1.py:6: AssertionError


运行结果可以看到最后一次失败了,因为第三次运行测试函数取的参数是 ("6*9", 42),54不等于42,所以断言失败。


2. 在参数化中标记单个测试实例


在参数化中标记单个测试实例,比如之前提到过的mark.xfail,这个可以标记测试函数为失败。那么在参数化中,如果想让其中的某个参数运行

的时候测试失败,就可以这样用:


import pytest
@pytest.mark.parametrize(
    "test_input,expected",
    [("3+5", 8), ("2+4", 6), pytest.param("6*9", 42, marks=pytest.mark.xfail)],
)
def test_eval(test_input, expected):
    assert eval(test_input) == expected


运行一下:


test_module1.py                                                       [100%]
======================== 2 passed, 1 xfailed in 0.05s =========================..x


3. 多个参数化组合,笛卡尔积


如果在测试函数上加了多个参数化装饰器,那么得到的参数组合是一个笛卡尔积:


import pytest
@pytest.mark.parametrize("x", [0, 1])
@pytest.mark.parametrize("y", [2, 3])
def test_foo(x, y):
    print("\nx:", x)
    print("y:", y)


应该会组合成4组数据x=0/y=2, x=1/y=2, x=0/y=3, 和x=1/y=3,测试函数执行4次:


test_module1.py .
x: 0
y: 2
.
x: 1
y: 2
.
x: 0
y: 3
.
x: 1
y: 3
                                                     [100%]
============================== 4 passed in 0.01s ==============================


二、用钩子函数pytest_generate_tests example拓展


如果有些场景需要动态的确定参数或者fixture的使用范围,那么可以使用pytest_generate_tests这个钩子函数,该函数会在收集测试函数时候被调用。

通过传入的metafunc对象,可以检查请求测试函数的上下文,还可以进一步的调用metafunc.parameterize()来实现参数化。


举例,有个测试函数需要接受输入的字符串作为参数,而且通过pytest命令行获取到,那么就要编写一个获取参数的fixture函数来给测试函数调用。


# content of test_strings.py
def test_valid_string(stringinput):
    assert stringinput.isalpha()


新建conftest.py文件,fixture函数写在这里:


# content of conftest.py
def pytest_addoption(parser):
    parser.addoption(
        "--stringinput",
        action="append",
        default=[],
        help="list of stringinputs to pass to test functions",
    )
def pytest_generate_tests(metafunc):
    if "stringinput" in metafunc.fixturenames:
        metafunc.parametrize("stringinput", metafunc.config.getoption("stringinput"))


现在用命令行方式来运行这个测试函数:pytest -q --stringinput="hello" --stringinput="world" test_strings.py,会运行2次。


D:\PycharmProjects\wms-api\interface\demo>pytest -q --stringinput="hello" --stringinput="world" test_strings.py
..                                                                                                                                                                     [100%]
2 passed in 0.01s


再换个输入参数,让测试函数失败:pytest -q --stringinput="!" test_strings.py


FAILED test_strings.py::test_valid_string[!] - AssertionError: assert False
1 failed in 0.04s


如果没有字符串输入,那么测试函数它将被跳过。因为metafunc.parameterize()被调用时,传过去的是一个列表:pytest -q -rs test_strings.py


SKIPPED [1] test_strings.py: got empty parameter set ['stringinput'], function test_valid_string at $REGENDOC_TMPDIR/test_strings.py:2
1 skipped in 0.12s


注意,在调用metafunc时, 如果使用不同的参数集进行多次参数化,这些参数集上的所有参数名称都不能重复,否则将会报错。


总结:文中讲到的3种用法,实际应用中第一种最常见,第二种次之,至于第三种,可以作为一些用法启发。

相关文章
|
19天前
|
存储 设计模式 测试技术
怎么基于Pytest+Requests+Allure实现接口自动化测试?
该文介绍了一个基于Python的自动化测试框架,主要由pytest、requests和allure构成,采用关键字驱动模式。项目结构分为六层:工具层(api_keyword)封装了如get、post的请求;参数层(params)存储公共参数;用例层(case)包含测试用例;数据驱动层(data_driver)处理数据;数据层(data)提供数据;逻辑层(logic)实现用例逻辑。代码示例展示了如何使用allure装饰器增强测试报告,以及如何使用yaml文件进行数据驱动。
|
2月前
|
Linux Android开发
测试程序之提供ioctl函数应用操作GPIO适用于Linux/Android
测试程序之提供ioctl函数应用操作GPIO适用于Linux/Android
30 0
|
2月前
|
JavaScript Java 测试技术
大学生体质测试|基于Springboot+vue的大学生体质测试管理系统设计与实现(源码+数据库+文档)
大学生体质测试|基于Springboot+vue的大学生体质测试管理系统设计与实现(源码+数据库+文档)
36 0
|
2月前
|
安全 测试技术 网络架构
【专栏】编写网络设备割接方案的七个步骤,包括明确割接目标、收集信息、制定计划、设计流程、风险评估、准备测试环境和编写文档。
【4月更文挑战第28天】本文介绍了编写网络设备割接方案的七个步骤,包括明确割接目标、收集信息、制定计划、设计流程、风险评估、准备测试环境和编写文档。通过实际案例分析,展示了如何成功完成割接,确保业务连续性和稳定性。遵循这些步骤,可提高割接成功率,为公司的网络性能和安全提供保障。
|
3天前
|
并行计算 监控 DataWorks
函数计算操作报错合集之测试函数时,报错“IndentationError: unexpected indent”,是什么原因
在使用函数计算服务(如阿里云函数计算)时,用户可能会遇到多种错误场景。以下是一些常见的操作报错及其可能的原因和解决方法,包括但不限于:1. 函数部署失败、2. 函数执行超时、3. 资源不足错误、4. 权限与访问错误、5. 依赖问题、6. 网络配置错误、7. 触发器配置错误、8. 日志与监控问题。
|
2天前
|
Java 测试技术
在Java中使用断言函数进行代码测试
在Java中使用断言函数进行代码测试
|
2月前
|
jenkins 测试技术 持续交付
Pytest测试框架
Pytest是一个功能强大的测试框架,支持单元测试和复杂功能测试,可结合Requests和Selenium等进行接口和自动化测试。它拥有超过315个插件,兼容unittest,并能与Allure、Jenkins集成实现持续集成。安装可通过pip或Pycharm。Pytest遵循特定命名规则,测试用例由名称、步骤和断言组成。断言用于验证预期结果,当失败时程序会终止。Pytest提供setup/teardown机制来管理测试前后的资源。
48 3
|
2月前
|
JavaScript Java 测试技术
基于ssm+vue.js的在线测试管理系统附带文章和源代码设计说明文档ppt
基于ssm+vue.js的在线测试管理系统附带文章和源代码设计说明文档ppt
17 0
|
2月前
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp的在线测试管理系统的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue+uniapp的在线测试管理系统的详细设计和实现(源码+lw+部署文档+讲解等)
276 0
|
2月前
|
数据可视化 数据挖掘 Java
springboot+vue体质测试数据分析及可视化设计(源码+文档)
体质测试数据分析及可视化设计实现了以下功能: 管理员:首页、个人中心、学生管理、教师管理、日常运动管理、运动分析管理、成绩信息管理、论坛管理、系统管理, 学生:首页、个人中心、日常运动管理、运动分析管理、成绩信息管理、论坛管理, 教师:首页、个人中心、日常运动管理、运动分析管理、成绩信息管理、系统管理, 前台首页:首页、论坛信息、公告信息、个人中心、后台管理、客服模块的修改维护操作。