接上 unittest+selenium实现WEB端UI自动化selenium+unittest+PO模式
pytest
- pytest
-
- 作用:
- 使用说明:
-
- 使用pytest创建测试用例
- 特殊函数
- 配置文件
- 执行测试用例
-
- [方式一:选择pytest为默认runner 右键执行](#方式一:选择pytest为默认runner 右键执行)
- 方式二:在terminal中使用pytest命令执行
- 方式三:main函数执行
- 方式四:pytest.ini+命令pytest
- 插件
- 跳过
- 参数化
- 断言
-
- [一、基本用法:直接用 `assert` 语句](#一、基本用法:直接用
assert
语句) - 二、进阶用法:常见场景的断言技巧
-
- [1. 检查异常(断言代码会抛出指定异常)](#1. 检查异常(断言代码会抛出指定异常))
- [2. 断言浮点数相等(处理精度问题)](#2. 断言浮点数相等(处理精度问题))
- [3. 断言列表/字典的部分元素](#3. 断言列表/字典的部分元素)
- [4. 断言对象属性](#4. 断言对象属性)
- 三、断言失败时的详细信息(pytest的优势)
- 四、与unittest断言的对比(为什么pytest更方便?)
- 总结
- [一、基本用法:直接用 `assert` 语句](#一、基本用法:直接用
pytest
作用:
- 是什么:
- 和unittest一样,都是一种单元测试框架
- pytest相比unittest,更简洁更高效,功能更强大
- unittest是python自带的,pytest是第三方库
- 在自动化测试中用于 管理和执行测试用例
- 特点:
- 1、非python官方自带,需下载安装
- 2、支持参数化
- 回忆,unittest本身不支持参数化是结合第三方插件parameterized
- pytest本身支持参数
- 3、支持跳过用例,支持给用例预期标注为失败
- 4、支持执行失败的case(重试)
- unittest不支持
- 5、支持简单的单元测试和复杂的功能测试用例执行
- 6、兼容性:支持运行Nose\unittest编写的测试用例脚本
- 7、可扩展性:具有很多第三方插件,也可以自定义
- 8、方便与持续集成结合
使用说明:
- 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、执行
- 1、安装pytest-html库
控制执行顺序的插件[pytest-order]
pytest-ordering
- 作用: 控制用例的执行顺序
- 使用步骤:
- 1、安装pytest-ordering库
pip install pytest-ordering
- 2、导入pytest库
import pytest
- 3、修饰被测函数或被测类
@pytest.mark.run(order=1)
- 1、安装pytest-ordering库
- 特点:
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")
- 优先级
优先级排序:
- 函数自身order → 函数所在类order→所在模块order
- 当order重复时,依赖模块名::类名::函数名的ascaii码排序
- 原则
- 优先在函数级别控制order 简单直观
- order尽可能值别重复
- 模块级别一般是控制业务模块整体顺序 比如订单模块在支付模块之后执行
重跑失败用例插件【pytest-rerunfailures】
- 作用:执行失败的用例,可能因特殊不稳定因素构成的,在自动化机制中添加失败重跑几次 提升成功率
- 步骤:
- 安装库pytest-rerunfailures
- 在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,...),...])
- 示例:
pythonimport pytest class TestLogin(): @pytest.mark.parameter(('name','pwd'),[('zx','123'),('lt','456')]) def test_login01(self,name,pwd): print(f"名字{name},密码{pwd}")
- 函数
pythonimport 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
相比 unittest
的 self.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
(浮点数)可解决复杂断言需求。
掌握这些技巧,就能轻松应对几乎所有测试场景的断言需求~