【pytest进阶】pytest详解及进阶使用

部署运行你感兴趣的模型镜像

pytest原理

参数化

@pytest.mark.parametrize(argnames, argvalues, indirect=False, ids=None, scope=None))

参数说明
argnames必传,参数名, 以逗号分隔的字符串,表示一个或多个参数名称(key),或参数字符串的列表/元组
argvalues必传,参数值,若argnames有一个则单值列表传入,若argnames有多个,以套用元组的列表展示,元组内与参数名一一对应
indirect为true时,那argnames一定是一个fixture函数名称,argvalues值将传入对应的fixture内,相当于@pytest.fixture(params=)的用法,默认False
ids标记子用例执行名称,与argvalues数量一致,未指定自动生成,默认None
scope如果指定,则表示参数的范围。范围用于按参数实例对测试进行分组。它还将覆盖任何fixture函数定义的范围,允许使用测试上下文或配置设置动态范围

案例

# 参数名 a,b,c,对应传入进去的参数a,b,c,需要一一对应。
@pytest.mark.parametrize("a,b,c",[(1,2,3),(7,8,15),(2,2,3),(9,6,15)])
def test_add(a,b,c):
    sum = a+b
    assert sum==c
 
# 组合参数化 :多组参数,依次组合,笛卡尔积
@pytest.mark.parametrize("x",[2,4,6])
@pytest.mark.parametrize("y",[1,3,5])
def test_add(x,y):
    print(f"x:{x},y:{y}")

pytest.ini

pytest配置文件可以改变pytest的运行方式,它是一个固定的文件pytest.ini文件,读取配置信息,按指定的方式去运行。

  • 位置:一般放在项目的根目录(即当前项目的顶级文件夹下)
  • 命名:pytest.ini,不能使用任何中文符号,包括汉字、空格、引号、冒号等等
  • 运行的规则:不管是主函数模式运行,命令行模式运行,都会自动读取这个全局配置文件。
  • 文件内容不支持中文(注释需要去掉)
[pytest]
# 指定pytest的命令行参数
addopts = -s # 输出print信息
          -v	# 输出详细信息
          -q    # 简化输出
          -k "TestClass and not test_2"  # 执行TestClass测试类下的方法,除了test_2
          -x    # 失败则退出执行
          -m xxx    # 只执行xxx标签的用例
          --clean-alluredir
          -reruns 3  # 失败重跑次数
 
# 注册标签
markers = xxx
 
# 测试用例文件搜索的目录
testpaths =
    ./test_case
# 测试用例文件/类/函数的命名规则
python_files = test_*.py
python_classes = Test*
python_functions = test_*
 
# --base-url插件,定义环境信息
base_url = http://www.baidu.com/
 
# 报告生成地址
alluredir = ./report/result
 
# 值为0时,显示所有用例的执行时间,统计后由大到小排序;(非0时,统计执行速度最慢的n条用例)
durations = 0
 
# 指定执行失败最大次数,超过则停止执行
maxfail=10

pytest.main使用

pytest.main([
        "-s", "-v",
        test_case,
        # mark_case,        # 执行标签用例
        # "-n", "auto",       # 分布式执行,以CPU核数为进程数执行
        # "-d", "--tx", "socket=127.0.0.1:8888", "--rsyncdir ./"  # 远程服务器分布式执行
        "--alluredir", "./report/result",   # allure报告数据生成地址
        # "--junit-xml", "./report/result.xml",
        "--clean-alluredir",
        "--durations=0",    # 值为0时,显示所有用例的执行时间,统计后由大到小排序;(非0时,统计执行速度最慢的n条用例)
        "--instafail",           # 实时打印错误信息,不使用则会最后才抛出所有错误信息
        "--reruns", "2",      # 失败重跑次数(用例方法也可指定重试次数,如:@pytest.mark.flaky(reruns=n))
        # " --reruns-delay", "2",      # 失败重跑后,下次测试重新开始之前等待的秒数。
        "--base-url", "http://123123",   # --base-url插件,定义环境信息(用例可以直接使用,如:def test_case(base_url))
        "--metadata", "author", "value1"   # --metadata参数添加键值对 (key, value) 的元数据
    ])

addopts配置

参数作用
-s表示输出调试信息,用于显示测试函数中print()打印的信息
-v未加前只打印模块名,加v后打印类名、模块名、方法名,显示更详细的信息
-q表示只显示整体测试结果
-vs这两个参数可以一起使用
-n支持多线程或者分布式运行测试用例(前提需安装:pytest-xdist插件)
–html生成html的测试报告(前提需安装:pytest-html插件) 如:pytest -vs --html ./reports/result.html
-x表示只要有一个测试用例报错,则执行停止
-k模糊匹配,测试用例的部分字符串,指定执行测试用例。
-mmark标记

pytest-xdist:远程多主机 - 分布式运行自动化测试

Fixture

fixture 相比setup和teardown的优势

  • 命名方式灵活,不局限于setup和teardown这几个命名
  • conftest 可以配置数据共享,
  • scope支持四个级别参数 "function" (默认), "class", "module" or "session"
  • 可通过 yield语句为测试函数区分前置条件和后置清理

Fixture参数详解及使用

【自动化测试】Pytest之Fixture参数详解及使用

多个fixture之间的相互调用

参数化的过程中也可以使用标记,比如标记为fail或者skip

使用fixture进行参数化

示例

# 参数化之 JSON 文件,Excel文件,Yaml文件,读到的数据是一个列表,列表里面嵌套列表,字典,元祖都可以,但是要和参数名称一一对应起来
# 创建一个 json 文件
{
  "login_param":
          [
            {
              "username": "aaa",
              "password": "aaa"
            },
            {
              "username": "bbb",
              "password": "bbb"
            },
            {
              "username": "ccc",
              "password": "ccc"
            },
            {
              "username": "ddd",
              "password": "ddd1"
            }
          ]
}
 
 
 
# conftest 文件代码
def read_login_json():
    with open("login.json", 'r', encoding="UTF-8") as f:
        data = json.load(f)['login_param']
    return data
 
 
# json参数化
@pytest.fixture(params=read_login_json())
def login_params(request):  # 参数 request固定写法
    return request.param  # requests.param 固定写法
 
 
# test_simple.py 文件
class TestDemo(object):
 
    def test_002(self, login_params):
        assert login_params["username"] == login_params["password"]
 
 
pytest.main(['test_simple.py::TestDemo',
             '-v', ])

pytest.mark.相关

给测试用例/测试类打标签

@pytest.mark.标签名

运行时设置只运行标签的用例

pytest -m 标签名

@pytest.mark.skip

跳过该用例

@pytest.mark.skipif

根据特定的条件,不执行标识的测试函数.
@pytest.mark.skipif(condition, reason=None)

  • condition:跳过的条件,必传参数
  • reason:标注原因,必传参数

使用方法:

@pytest.mark.skipif(1==1, reason="跳过说明")

@pytest.mark.xfail

标记测试函数预期为失败函数
xfail(condition=None, reason=None, raises=None, run=True, strict=False)

  • condition:预期失败的条件,必传参数
  • reason:失败的原因,必传参数

@pytest.mark.repeat(重复测试)

@pytest.mark.repeat(3) # 这个测试用例会运行三次。

@pytest.mark.dependency(用例依赖)

标记测试用例之间的依赖关系,以确保在需要的测试用例之前运行先决条件

@pytest.mark.dependency()
def test_login():
    assert True
@pytest.mark.dependency(depends=["test_login"])
def test_access_profile():
    assert True
@pytest.mark.dependency(depends=["test_login"])
def test_access_settings():
    assert True

失败重运行

用例失败的情况下,可以重运行用例。

需要安装插件rerunfailures

pip install pytest-rerunfailures

使用方法

pytest --reruns 3 --rerun-dalay 2 
pytest --reruns {运行失败的用例可以重新运行次数} --rerun-dalay {每次重试之间的延时设置(单位:秒)}  

 

指定用例的运行顺序

pytest有自己的用例执行顺序,但有时候我们就是想指定它按照我的方式去执行,需要使用pytest-ordering插件

安装插件pytest-ordering

pip install pytest-ordering

使用方法

# 方式一:
第一个执行:  @ pytest.mark.run('first')
第二个执行:  @ pytest.mark.run('second')
倒数第二个执行: @ pytest.mark.run('second_to_last')
最后一个执行:  @ pytest.mark.run('last')
 
# 方式二:
第一个执行:  @ pytest.mark.first
第二个执行:  @ pytest.mark.second
倒数第二个执行:   @ pytest.mark.second_to_last
最后一个执行:    @pytest.mark.last
 
# 方式三:
第一个执行:  @ pytest.mark.run(order=1)
第二个执行:  @ pytest.mark.run(order=2)
倒数第二个执行:   @ pytest.mark.run(order=-2)
最后一个执行:     @ pytest.mark.run(order=-1)

执行优先级:0>较小的正数>较大的正数>无标记>较小的负数>较大的负数

pytest的hook函数

【pytest进阶】pytest之hook函数

pytest项目实战

pytest自定义参数

项目主目录创建conftest.py文件

import pytest
from base.driver import Driver
from tools.unit import logger
 
 
def pytest_addoption(parser):
    parser.addoption(
        "--devices", action="store", default="", help="devices:表示设备信息,默认取配置文件"
    )
    logger.info('添加pytest自定义参数:--devices')
 
 
@pytest.fixture(autouse=True, scope='session')  # pytest.fixture标签进行获取自定义参数
def drivers(request):
    return request.config.getoption("--devices")
 
 
@pytest.fixture(scope='session')  # pytest.fixture标签进行获取自定义参数
def get_device(drivers):
    if drivers:
        dv = eval(drivers)
        logger.info("开始与设备 {} 进行会话,并执行测试用例 !!".format(dv["deviceName"]))
        driver = Driver(dv)
        yield driver.get_driver()
        driver.close()
    else:
        logger.info("取配置文件设置的driver")
        driver = Driver()
        yield driver.get_driver()      # 返回内容
        driver.close()                 # 后置处理

用例中引用

class TestLogin(SetupTeardown):
 
    @pytest.mark.run(order=1)
    @pytest.mark.smock
    @pytest.mark.dependency()
    def test_login_001(self, get_device):    # get_device为自定义参数返回内容
        self.driver = get_device
        logging.info('==========test_login_001========')
        LoginPage(self.driver).login("user123", "password123")

使用方法

pytest --devices {参数内容}

用例使用自定义装饰器

【自动化测试】装饰器与出错重试机制

您可能感兴趣的与本文相关的镜像

Python3.9

Python3.9

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

<think>好的,我现在需要详细回答用户关于pytest中assert语句的用法和示例的问题。首先,我得回忆一下pytest的断言机制,和标准的Python assert有什么不同。记得pytest会重写assert语句,提供更详细的错误信息,这点很重要。 用户可能已经知道基本的assert用法,比如assert 1 == 2,但需要更深入的例子。我应该涵盖不同类型的断言,比如等式、不等式、包含、异常等。还要注意是否需要解释pytest如何自动捕获断言错误,并展示失败的具体信息。 然后,根据用户提供的引用,特别是引用[4],里面提到关键代码是“assert 表达式, 错误提示信息”,这说明用户可能需要关于自定义错误消息的例子。例如,当断言失败时,如何添加更清晰的提示,这需要给出示例,比如assert a == b, "数值不相等"。 接下来,我得组织内容结构。可能需要分点说明,比如基本用法、扩展断言、自定义错误信息、与第三方库的结合使用,比如NumPy的数组比较。这样结构更清晰,用户容易理解。 另外,用户提供的引用中有关于fixture和其他pytest用法的内容,虽然问题主要关注assert,但可能需要确保回答专注于断言部分,但如果有相关结合使用的例子,比如在fixture中使用断言,可能也需要提及,不过可能不太常见。 还需要检查是否有常见的陷阱或注意事项,比如在断言中使用生成器表达式可能导致的问题,或者某些对象比较需要特定方法,比如浮点数近似比较。比如,pytest.approx的使用,应该作为一个示例,因为这在测试数值时很常见。 然后,考虑用户可能的进阶需求,比如如何处理异常断言,使用pytest.raises上下文管理器。这也是assert语句的一部分,需要详细说明和示例。 最后,生成相关问题,确保问题覆盖用户可能感兴趣的周边知识点,比如fixture的使用、测试顺序、参数化测试等,但要根据引用中的内容来生成,比如引用[2]、[3]、[5]提到的fixture和执行顺序,所以相关问题可以涉及这些方面。 现在,需要确保所有示例代码正确,符合LaTeX格式要求,行内公式用$...$,独立公式用$$...$$。但在这个问题中,可能数学公式不多,主要是代码块,所以要注意代码块的格式是否正确,用三个反引号包裹,并标明语言。 检查是否有遗漏的重要用法,比如集合的断言,字典的键值是否存在,或者使用正则表达式匹配字符串。这些也是常见的测试场景,应该包括进去。 总结,回答的结构应该是: 1. 基本用法:展示简单的等式、不等式断言。 2. 扩展断言类型:包含、类型检查、异常。 3. 自定义错误信息:如何在断言后添加消息。 4. 高级用法:比如浮点数近似比较,使用第三方库的数据结构。 5. 注意事项:比如避免在断言中执行有副作用的操作。 每个部分都需要代码示例,并确保正确性。同时,引用相关的引用内容,比如引用[4]中的例子,需要正确标注引用标识。 最后,生成的相关问题要基于用户提供的引用,比如关于fixture的使用、测试顺序、断言失败的处理等,这样能引导用户继续深入学习相关内容。</think>### pytest断言(assert)使用详解 pytest的断言机制通过重写Python原生`assert`语句实现自动化测试验证,具有智能错误提示功能。以下是具体用法分类说明: #### 一、基础断言语法 ```python def test_math_operations(): # 等式验证 assert 5 + 3 == 8 # 正常通过 assert 2**3 == 7, "幂运算验证失败" # 触发AssertionError[^4] # 包含关系验证 assert 'hello' in 'hello world' assert 4 not in [1, 2, 3] ``` #### 二、扩展断言类型 ```python import pytest def test_data_structures(): # 集合比对 assert {'a': 1, 'b': 2} == {'b': 2, 'a': 1} # 字典无序性验证 # 类型检查 assert isinstance(3.14, float) # 异常捕获(必须使用pytest上下文管理器) with pytest.raises(ZeroDivisionError): _ = 1 / 0 ``` #### 三、高级验证方法 ```python def test_floating_point(): # 浮点数近似比较 assert 0.1 + 0.2 == pytest.approx(0.3, rel=1e-5) def test_numpy_data(): # 数组比对(Numpy专用) import numpy as np arr1 = np.array([1.0, 2.0]) arr2 = np.array([1.0, 2.001]) assert np.allclose(arr1, arr2, atol=0.01) ``` #### 四、自定义错误信息 ```python def test_user_message(): actual = 100 expected = 95 # 带调试信息的断言 assert actual == expected, f"预期值误差超过5%,实际值:{actual},预期值:{expected}" ``` #### 五、断言优化建议 1. 避免在断言中执行修改操作(如`assert list.pop()`) 2. 复杂对象建议使用专门比对方法(如`assertDictEqual`) 3. 大数据集验证优先检查关键特征值 $$ \text{断言执行效率公式:} T = k \times n + C \quad (n\text{为数据规模}) $$
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

慕城南风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值