pytest 实战:用例管理、插件技巧、断言详解

接上 unittest+selenium实现WEB端UI自动化selenium+unittest+PO模式

pytest

pytest

作用:

  • 是什么:
    • 和unittest一样,都是一种单元测试框架
    • pytest相比unittest,更简洁更高效,功能更强大
    • unittest是python自带的,pytest是第三方库
    • 在自动化测试中用于 管理和执行测试用例
  • 特点:

使用说明:

  • pytest是第三方,需要安装
    pip install pytest
  • 验证pytest安装成功
    cmd 命令行pytest --version
    • 如果无法识别pytest指令,则用管理员方式再次安装一遍

使用pytest创建测试用例

一、测试函数方式
  • 1、创建以test开头的测试方法

pytest_test01.py:

python 复制代码
def test_login():
	print("这是一个测试函数")
二、测试类方式
  • 1、创建一个以test开头的类
  • 2、在类中创建以test开头的方法
python 复制代码
"""
测试类方式创建测试用例
"""


class TestLogin():

    def test_login1(self):
        print("登录测试用例1")

    def test_login2(self):
        print("登录测试用例2")

特殊函数

类比unittest中的FixTure,在pytest中 是由固定名字的函数

函数级别
python 复制代码
class TestLogin():
	def setup():
		print("函数开始")

	def teardown():
		print("函数结束")

	def test_login1():
		print("测试函数1")
	
	def test_login2():
		print("测试函数2")
		
类级别
python 复制代码
class TestLogin():
	def setup_class(self):
		print("类开始")

	def teardown_class(self):
		print("类结束")

	def test_login1(self):
		print("测试函数1")
	
	def test_login2(self):
		print("测试函数2")

配置文件

在terminal中输入pytest --help指令,查看和配置文件相关的信息

  • 作用:

    • 配置测试用例规则
    • 配置测试报告
    • 。。。等关于自动化测试管理和执行一些规则
  • 配置文件结构

    • 首行:[pytest]声明文件格式
    • 2-n行:写配置信息
    • 示例(默认配置):
    python 复制代码
    [pytest]
    testpaths = ./cases
    python_files = test*.py
    python_classes = Test*
    python_functions = test*
    addopts = -s
    复制代码
      - testpaths:存放用例的路径
      - python_files: 文件名规则
      - python_classes:指定用例类规则
      - python_functions:指定用例方法名规则
      - addopts : 执行测试用例时额外添加的命令行
  • 配置文件注意事项:

    • 一个项目写一个配置文件即可
    • 一般配置文件放到项目根目录下
    • Windows系统下的ini文件不允许写注释-无法解析

执行测试用例

方式一:选择pytest为默认runner 右键执行
  • 更改pycharm设置,选择pytest为默认runner
    【File】-【Settings】-【Tools】-【python Integrated Tools】
方式二:在terminal中使用pytest命令执行
  • 1、打开terminal命令窗口
  • 2、使用terminal在当前文件目录下执行pytest -s pytest_test01.py
    • -s 代表执行测试函数并输出信息
    • 不带-s 则仅执行不输出
方式三:main函数执行
  • 1、导入pytest
  • 2、在main函数中编写pytest.main(['-s',"文件名.py"])
python 复制代码
import pytest

if __name__ == '__main__':

    pytest.main(['-s','pytest_test01.py'])
方式四:pytest.ini+命令pytest

插件

html报告插件【pytest-html】
  • 作用: 用于生成HTML格式的测试报告
  • 使用步骤:
    • 1、安装pytest-html库
      • pip install pytest-html
    • 2、更改配置文件addopts,指定报告生成位置
      • --html = 文件路径/文件名.html
      • --html = 文件路径/文件名.html --self-contained-html 合并css文件 可选
    • 3、执行
控制执行顺序的插件[pytest-order]
pytest-ordering
  • 作用: 控制用例的执行顺序
  • 使用步骤:
    • 1、安装pytest-ordering库
      pip install pytest-ordering
    • 2、导入pytest库
      import pytest
    • 3、修饰被测函数或被测类
      @pytest.mark.run(order=1)
  • 特点:
    1、可以修饰函数 也可以修饰类
    2、order值可为正数、也可为负数
    • 全正:从小到大执行
    • 全负:从小到大执行
    • 有正有负:被标记为正数的优先级高于负数
pytest-order

最新维护的插件pytest-order

  • 使用步骤:

    • 安装pip install pytest-order
    • 标记测试类、测试函数、模块@pytest.mark.order(数字)
  • 特点:

    1、支持正数、负数

    • 同时存在正数、负数时,负数优先级高
    • 负数 一般用于数据配置等前置曹祖
    • 正数 用于标记业务顺序
    • 未被标记的用例,在所有标记用例之后执行
    • 用例被标记同一个顺序,按照函数名的ASCAII码顺序

    2、可修饰测试类、测试函数、模块

修饰模块

在模块内添加pytestmark = pytest.mark.order(2)

python 复制代码
import pytest

pytestmark = pytest.mark.order(1)

class TestRegister():

    def test_register1(self):
        print("测试注册1")

    def test_register2(self):
        print("测试注册2")
修饰类
python 复制代码
import pytest
@pytest.mark.order(1)
class TestRegister():

    def test_register1(self):
        print("测试注册1")

    def test_register2(self):
        print("测试注册2")
修饰函数
python 复制代码
import pytest

class TestRegister():
	@pytest.mark.order(2)
    def test_register1(self):
        print("测试注册1")
	@pytest.mark.order(1)
    def test_register2(self):
        print("测试注册2")
  • 优先级
    优先级排序:
  1. 函数自身order → 函数所在类order→所在模块order
  2. 当order重复时,依赖模块名::类名::函数名的ascaii码排序
  • 原则
  1. 优先在函数级别控制order 简单直观
  2. order尽可能值别重复
  3. 模块级别一般是控制业务模块整体顺序 比如订单模块在支付模块之后执行
重跑失败用例插件【pytest-rerunfailures】
  • 作用:执行失败的用例,可能因特殊不稳定因素构成的,在自动化机制中添加失败重跑几次 提升成功率
  • 步骤:
    1. 安装库pytest-rerunfailures
    2. 在pytest.ini配置文件中添加addopts = --reruns 重跑次数 一般1~3次适宜

跳过

skip
  • 作用:批量用例执行时,被标记为skip的用例 跳过不执行
  • 语法:@pytest.mark.skip
  • 作用范围:
    • 可标记测试函数
    • 可标记测试类
skipif
  • 作用:批量用例执行时,被标记为skipif的用例,符合条件则跳过执行
  • 语法:@pytest.mark.skipif(conditions,reasons="跳过的原因")
  • 作用范围:
    • 可标记测试函数
    • 可标记测试类

参数化

pytest自身支持参数化,不需额外安装第三方库

  • 语法:@pytest.mark.parameter((参数1,参数2,参数3,...),[(数值1-1,数值1-2,...),(数值2-1,..),(数值3-1,...),...])

    • 示例:
    python 复制代码
    import pytest
    class TestLogin():
    	@pytest.mark.parameter(('name','pwd'),[('zx','123'),('lt','456')])
    	def test_login01(self,name,pwd):
    		print(f"名字{name},密码{pwd}")
    • 函数
    python 复制代码
    import pytest
    def build_data():
    	return [('zx','123'),('lt','456')]
    class TestLogin():
    	@pytest.mark.parameter(('name','pwd'),build_data())
    	def test_login01(self,name,pwd):
    		print(f"名字{name},密码{pwd}")

断言

pytest使用python自带的断言assert

pytest 中,断言(Assertion)是验证测试结果是否符合预期的核心方式。与 unittest 不同,pytest 不依赖特定的断言方法(如 self.assertEqual()),而是直接使用 Python 内置的 assert 语句 ,配合 pytest 的"断言重写"机制,能自动生成更详细的错误信息,使用更简洁、灵活。

一、基本用法:直接用 assert 语句

pytest 完全兼容 Python 原生的 assert 语法,只需在测试用例中用 assert 表达式 即可。若表达式为 False,则断言失败,测试用例报错;若为 True,则断言成功。

示例:基础断言
python 复制代码
def test_basic_assert():
    # 1. 比较值是否相等
    assert 1 + 1 == 2  # 成功(表达式为True)
    
    # 2. 检查布尔值(True/False)
    assert True  # 成功
    assert not False  # 成功(not False → True)
    
    # 3. 检查包含关系(字符串、列表、字典等)
    assert "hello" in "hello world"  # 字符串包含
    assert 2 in [1, 2, 3]  # 列表包含
    assert "name" in {"name": "张三", "age": 18}  # 字典包含键
    
    # 4. 检查对象是否为None
    result = None
    assert result is None  # 成功
    
    # 5. 自定义失败提示(在assert后加逗号和提示文字)
    a = 10
    b = 20
    assert a == b, f"预期{a}等于{b},实际不相等"  # 失败时显示:预期10等于20,实际不相等
二、进阶用法:常见场景的断言技巧

除了基础比较,pytest 结合 Python 语法可轻松实现复杂场景的断言,以下是高频使用场景:

1. 检查异常(断言代码会抛出指定异常)

使用 pytest.raises 作为上下文管理器,断言"执行某段代码时会抛出预期的异常",适合测试错误处理逻辑。

python 复制代码
import pytest

def divide(a, b):
    if b == 0:
        raise ValueError("除数不能为0")
    return a / b

def test_raise_exception():
    # 断言调用divide(1, 0)时会抛出ValueError,且错误信息包含"除数不能为0"
    with pytest.raises(ValueError) as exc_info:
        divide(1, 0)
    
    # 进一步断言异常信息
    assert "除数不能为0" in str(exc_info.value)
  • exc_info.value:获取抛出的异常对象;
  • 若代码未抛出异常,或抛出的异常类型不匹配,则断言失败。
2. 断言浮点数相等(处理精度问题)

浮点数直接用 == 比较可能因精度误差失败(如 0.1 + 0.2 = 0.30000000000000004),需用 pytest.approx() 处理。

python 复制代码
def test_float_assert():
    result = 0.1 + 0.2
    # 错误方式:直接比较会失败(因精度问题)
    # assert result == 0.3  # 失败
    
    # 正确方式:用pytest.approx()处理精度
    assert result == pytest.approx(0.3)  # 成功

pytest.approx() 支持自定义精度(默认相对误差1e-6):

python 复制代码
assert 1.0000001 == pytest.approx(1.0, abs=1e-6)  # abs=绝对误差阈值
3. 断言列表/字典的部分元素

无需完整比较列表/字典,可只断言其中的关键元素。

python 复制代码
def test_list_dict_assert():
    # 断言列表中包含指定元素(不关心顺序)
    user_list = ["张三", "李四", "王五"]
    assert "李四" in user_list  # 成功
    
    # 断言字典包含指定键值对(不关心其他键)
    user_info = {"name": "张三", "age": 18, "gender": "男"}
    assert user_info["name"] == "张三"  # 断言name的值
    assert user_info.get("age") == 18  # 用get()避免KeyError
4. 断言对象属性

对于类实例,可直接断言其属性值。

python 复制代码
class User:
    def __init__(self, name, age):
        self.name = name
        self.age = age

def test_object_assert():
    user = User("张三", 18)
    assert user.name == "张三"  # 断言name属性
    assert user.age > 16  # 断言age满足条件
三、断言失败时的详细信息(pytest的优势)

pytest 会对 assert 语句进行"重写"(assert rewriting),当断言失败时,不仅会提示"断言失败",还会显示 表达式中各部分的具体值,方便定位问题。

例如,执行以下测试:

python 复制代码
def test_assert_detail():
    a = 10
    b = 20
    assert a + 5 == b  # 10 + 5 = 15 ≠ 20 → 失败

pytest 会输出详细错误信息:

复制代码
E       assert (10 + 5) == 20
E        +  where 10 = a
E        +  and   20 = b

相比 unittestself.assertEqual(a+5, b)pytest 的错误信息更直观,无需记忆复杂的断言方法。

四、与unittest断言的对比(为什么pytest更方便?)
场景 unittest 断言(繁琐) pytest 断言(简洁)
比较相等 self.assertEqual(a, b) assert a == b
检查包含 self.assertIn(x, list) assert x in list
检查异常 self.assertRaises(ValueError, func) with pytest.raises(ValueError): func()
自定义提示 self.assertEqual(a, b, msg) assert a == b, msg

pytest 完全兼容 Python 原生语法,无需学习新的断言API,上手成本极低。

总结
  • pytest 断言的核心是 Python 内置的 assert 语句,简洁灵活,无需记忆特定方法;
  • 支持丰富场景:值比较、异常检查、浮点数精度、对象属性等;
  • 断言失败时自动生成详细错误信息(含变量值),调试效率高;
  • 结合 pytest.raises(异常)和 pytest.approx(浮点数)可解决复杂断言需求。

掌握这些技巧,就能轻松应对几乎所有测试场景的断言需求~

相关推荐
资源补给站4 小时前
服务器高效操作指南:Python 环境退出与 Linux 终端快捷键全解析
linux·服务器·python
一苓二肆4 小时前
代码加密技术
linux·windows·python·spring·eclipse
青春不败 177-3266-05204 小时前
AI+Python驱动的无人机生态三维建模与碳储、生物量、LULC估算技术
人工智能·python·无人机·生态学·遥感·多光谱遥感
将车2444 小时前
selenium实现自动化脚本的常用函数
python·selenium·自动化
ZhengEnCi4 小时前
Excel 文件结构完全指南-从基础概念到 Python 读取的实用宝典
python·excel
一百天成为python专家4 小时前
python爬虫入门(小白五分钟从入门到精通)
开发语言·爬虫·python·opencv·yolo·计算机视觉·正则表达式
程序员二黑4 小时前
Selenium元素定位总失败?这8种定位策略你必须掌握
单元测试·测试·ab测试
simon_skywalker4 小时前
第十二章 序列的特殊方法
python
ZhengEnCi4 小时前
FastAPI 项目结构完全指南-从零基础到企业级应用的 Python Web 开发利器
服务器·python·web3