Pytest的使用
1.Pytest安装和介绍
1. Pytest介绍
pytest是python的一种单元测试框架,同自带的Unittest测试框架类似,相比于Unittest框架使用起来更简洁,效率更高.
2. Pytest特点
1.非常容易上手,入门简单,文档丰富,文档中有很多实例可以参考
2.支持简单的单元测试和复杂的功能测试.
3.支持参数化.
4.执行测试过程中可以将某些测试跳过,或者对某些预期失败的Case标记成失败
5.支持重复执行失败的Case.
6.支持运行由Nose,Unittest编写的测试Case
7.具有很多第三方插件,并且可以自定义扩展
8.方便的和持续集成工具集成.
3.Pytest安装
安装命令: pip install -U pytest
参数解释:
-U 是upgrade, 表示已安装就升级为最新版本.
安装成功校验: pytest --version # 会展示当前已安装版本
4. pytest第一个例子
# 创建文件: test_abc.py
import pytest
def test_a():
print("---->test_a")
# 断言成功
assert 1
def test_b():
print("---->test_b")
# 断言失败
assert 0
if __name__ == "__main__":
pytest.main("-s. test_abc.py")
执行结果:
test_abc.py
------->test_a
. # .(代表成功)
------->test_b
F # F(代表失败)
5. 运行方式
5.1 测试类主函数模式
pytest.main("-s test_abc.py")
5.2 命令行模式
pytest。文件路径/测试文件名
例如: pytest ./test_abc.py
2.setup和teardown函数
学习目标
- 能够区分setup和teardown函数在函数级别和类级别的不同
1. 概述
1. setup和teardown函数主要分为:模块级、类级、功能级、函数级别、
2. 存在于测试类内部
2. 函数级别的setup和teardown函数
特点:
当是函数级别的时候,运行测试方法的始末,即运行一次测试函数运行一次setup和teardown.
import pytest
class Test_ABC:
def setup(self):
print("-----> setup_method")
def teardown(self):
print("----> teardown_method")
def test_a(self):
print("----> test_a")
assert 1
def test_b(self):
print("----> test_b")
if __name__ == "__main__":
pytest.main("-s test02.py")
执行结果
test_abc.py
------->setup_method # 第一次 setup()
------->test_a
.
------->teardown_method # 第一次 teardown()
------->setup_method # 第二次 setup()
------->test_b
.
------->teardown_method # 第二次 teardown()
3. 类级别
特点:
运行于测试类的始末,即:在一个测试内只运行一次setup_class和teardown_class,不关心测试类 内有多少个测试函数.
import pytest
class Test_ABC:
def setup_class(self):
print("-----> setup_class")
def teardown_class(self):
print("----> teardown_class")
def test_a(self):
print("----> test_a")
assert 1
def test_b(self):
print("----> test_b")
if __name == "__main__":
pytest.main("-s test_abc.py")
执行结果
test_abc.py
------->setup_class # 第一次 setup_class()
------->test_a
.
------->test_b
F
------->teardown_class # 第一次 teardown_class()
3. pytest配置文件
pytest的配置文件通常放在测试目录下,名称为pytest.ini,命令运行时会使用该配置文件中的配置
- 配置pytest命令行运行参数
[pytest]
addopts = -s ... # 空格分隔,可添加多个命令行参数 -所有参数均为插件包的参数
- 配置测试搜索的路径
[pytest]
testpaths = ./scripts # 当前目录下的scrip文件夹 可自定义
- 配置测试搜索的文件名
[pytest]
python_files = test_*.py
# 当前目录下的scripts文件夹下,以test_开头,以.py结尾的所有文件 -可自定义
- 配置测试搜索的测试类名
[pytest]
python_classes = Test_*
# 当前目录下的scripts文件夹下,以test_开头,以.py结尾的所有文件中,以Test_开头的类
- 配置测试搜索的测试函数名
[pytest]
python_functions = test_*
# 当前目录下的scripts文件夹下,以test_开头,以.py结尾的所有文件中,以Test_开头的类内,以test_开头的⽅法 -可自定义
4.常用插件
学习目标
- 掌握常用的插件
- 知道查找需要安装插件的方法
1. 概述
pytest包含很多插件包,可以根据需求选择安装即可.
我们这里只讲解常用的!!
2. 前置条件
1.文件路径:
- Test_App
- - test_abc.py
- - pytest.ini
2.pyetst.ini配置文件内容:
[pytest]
# 命令行参数
addopts = -s
# 搜索文件名
python_files = test_*.py
# 搜索的类名
python_classes = Test_*
# 搜索的函数名
python_functions = test_*
3.常用插件
3.1 pytest测试报告
作用: 通过命令行方式,生成xml/html格式的测试报告,存储于用户指定路径。
**安装方式: ** pip install pytest-html
使用方法:
命令行格式: pytest —html=存储路径/report.html
**示例代码1 **
import pytest
class Test_ABC:
def setup_class(self):
print("-----> setup_class")
def teardown_class(self):
print("----> teardown_class")
def test_a(self):
print("----> test_a")
assert 1
def test_b(self):
print("----> test_b")
assert 0
同时更改配置文件
-
修改Test_App/pytest.ini文件,添加报告参数,即:addopts = -s --html=./report.html
参数解释:
- -s是输出程序运行信息
- —html=./report.ml 在当前目录下生成report.html文件
⚠️ 若要生成xml文件,可将–html=./report.html 改成 --html=./report.xml
3.2 Pytest 控制函数执行顺序
默认情况下,pytest是根据测试方法名由小到大执行的,可以通过第三方插件包改变其运行顺序。
作用: 以函数修饰符的方式标记被测函数,通过参数控制函数执行顺序
安装插件: pip install purest-ordering
使用方法:
- 标记于被测函数, @pytest.mark.run(order=x)
- 根据order传入参数来决定运行顺序:
- order值全为正数或全为负数时, 值越小,优先级越高
- 正数和负数同时存在,正数优先级高
示例代码2
import pytest
class Test_ABD:
def setup_class(self):
print("-----> setup_class")
def teardown_class(self):
print("----> teardown_class")
@pytest.mark.run(order=2)
def test_a(self):
print("----> test_a")
assert 1
@pytest.mark.run(order=1)
def test_b(self):
print("----> test_b")
assert 0
if __name__ == "__main__":
pytest.main("-s test_abc.py")
执行结果:
test_abc.py
------->setup_class
------->test_b # order=1 优先运行
F
------->test_a # order=2 晚于 order=1 运行
.
------->teardown_class
3.3 失败重试
插件名称: pytest-rerunfailures
作用: 使用命令行方式,控制失败函数的重试次数.
安装方式: pip install purest-rerunfailures
使用方法:
命令行格式, pytest —rerun n # n为重试的次数
示例代码3
import pytest
class Test_ABD:
def setup_class(self):
print("-----> setup_class")
def teardown_class(self):
print("----> teardown_class")
def test_a(self):
print("----> test_a")
assert 1
def test_b(self):
print("----> test_b")
assert 0
if __name__ == "__main__":
pytest.main("-s test_abc.py")
修改配置文件 , 修改Test_App/pytest.ini文件,添加失败重试参数,即:addopts = -s --reruns 2 --html=./report.html
参数解释:
- -s是输出程序运行信息
- —rerun 2 : 失败重试2次
- —html=./report.ml 在当前目录下生成report.html文件
5.pytest提高–fixture
学习目标
- 掌握fixture的作用
- 掌握fixture的使用方法
1. 简介
fixture是pytest特有的功能,它用pytest.fixture标识,以装饰器形式定义在函数上面,在编写测试函数的时候,可以将此函数名称做为传入参数,pytest将会以依赖注入方式,将该函数的返回值作为测试函数的传入参数.
fixture有明确的名字,在其他函数,模块,类或整个工程调用它时会被激活。
fixture是基于模块来执行的,每个fixture的名字就可以触发一个fixture的函数,它自身也可以调用其他的fixture.
我们可以把fixture看做是资源,在你的测试用例执行之前需要去配置这些资源,执行完后需要去释放资源。比如module类型的fixture,适合于那些许多测试用例都只需要执行一次的操作。
fixture还提供了参数化功能,根据配置和不同组件来选择不同的参数。
2. fixture函数的作用
fixture修饰器来标记固定的工厂函数,在其他函数,模块,类或整个工程调用它时会被激活并优先执行,通常会被用于完成预置处理和重复操作。
例如,
- 在测试网站的功能时,每个测试用例都要登录和退出,利用fixture就可以只做一次,否则每个测试用例都要做这两步也是冗余。
- 完成setup和teardown操作,处理数据库或文件的打开、关闭操作
- 准备测试数据.将数据提前写入数据库或通过params返回给测试用例
3. 使用方法
pytest.fixture(scope='function', params=None, autouse=False, ids=None, name=None)
常用参数解释:
- scope: 被标记方法的作用域;
"function": 默认值,表示每个测试方法都要执行一次
"class": 作用于整个类, 表示每个类的所有测试方法只运行一次
"module": 作用于整个模块, 每个module的所有测试方法只运行一次.
"session": 作用于整个session, 每次session只运行一次. ⚠️(此方法慎用!!)
- params: list类型,默认None, 接收参数值,对于param里面的每个值,fixture都会去遍历执行一次.
- autouse: 是否自动运行,默认为false, 为true时此session中的所有测试函数都会调用fixture
⚠️ 以上的所有参数也可以不传
4. 使用案例
4.1 基本使用–作为参数应用
import pytest
@pytest.fixture()
def before():
print("-----> 在每个函数前执行")
def test_1(before):
print('-----> test_1')
assert 1
def test_2(before):
print("----> test_2")
assert 0
if __name__ == "__main__":
pytest.main("-s test_1.py")
结果
test_fixture.py::test_1
----->在每个函数执行之前
PASSED [ 50%]-----> test_1
test_fixture.py::test_2
----->在每个函数执行之前
FAILED [100%]----> test_2
4.2 基本使用–作为函数应用
import pytest
@pytest.fixture()
def before():
print('\nbefore each test')
@pytest.mark.usefixtures("before")
def test_1():
print('--->test_1')
@pytest.mark.usefixtures("before")
def test_2(before):
print("----> test_2")
@pytest.mark.usefixtures("before")
class Test2:
def test_5(self):
print('test_5')
def test_6(self):
print('test_6')
if __name__ == "__main__":
pytest.main("-s test_1.py")
基本使用中我们发现结果基本是类似的,都是在每个测试函数前被调用执行.
结果
test_fixture.py::test_1 -----> 在每个函数前执行
PASSED [ 50%]-----> test_1
test_fixture.py::test_2 -----> 在每个函数前执行
FAILED [100%]----> test_2
[100%]test_6
4.3 带参数使用—设置为默认启动形式
设置true,是自动运行, 代表这个session的所有测试函数都会调用
import pytest
@pytest.fixture(autouse=True)
def before():
print('\nbefore each test')
class Test2:
def test_5(self):
print('test_5')
def test_6(self):
print('test_6')
if __name__ == "__main__":
pytest.main("-s test_1.py")
结果
test_fixture.py::Test2::test_5
before each test
PASSED [ 50%]test_5
test_fixture.py::Test2::test_6
before each test
PASSED [100%]test_6
4.4 带参数使用—设置作用域为function
设置为function, 表示每个测试方法都要执行一次
import pytest
@pytest.fixture(scope="function", autouse=True)
def before():
print('\nbefore each test')
class Test2:
def test_5(self):
print('test_5')
def test_6(self):
print('test_6')
if __name__ == "__main__":
pytest.main("-s test_1.py")
结果
test_fixture.py::test_1
before each test
PASSED [ 33%]--->test_1
test_fixture.py::Test2::test_5
before each test
PASSED [ 66%]
test_5
test_fixture.py::Test2::test_6 PASSED [100%]
test_6 [ 66%]test_5
4.5 带参数使用— 设置作用域为class
作用于整个类, 表示每个类的所有测试方法只运行一次
import pytest
@pytest.fixture(scope="class", autouse=True)
def before():
print('\nbefore each test')
@pytest.mark.usefixtures("before")
def test_1():
print('--->test_1')
class Test2:
def test_5(self):
print('test_5')
def test_6(self):
print('test_6')
if __name__ == "__main__":
pytest.main("-s test_1.py")
结果
test_fixture.py::test_1
before each test
PASSED [ 33%]--->test_1
test_fixture.py::Test2::test_5
before each test
PASSED [ 66%]test_5
test_fixture.py::Test2::test_6 PASSED [100%]test_6
4.6 带参数使用— 设置作用域为module
作用于整个模块, 表示这个模块的只运行一次fixture, 例如所有的test都需要连接同一个数据库,可以使用此方法,对于此模块的所有test都有效
import pytest
@pytest.fixture(scope="module", autouse=True)
def before():
print('\nbefore each test')
@pytest.mark.usefixtures("before")
def test_1():
print('--->test_1')
class Test2:
def test_5(self):
print('test_5')
def test_6(self):
print('test_6')
if __name__ == "__main__":
pytest.main("-s test_1.py")
结果
test_fixture.py::test_1
before each test
PASSED [100%]--->test_1
4.7 带参数使用— fixture 返回值
默认为none, 传入list类型参数, fixture会遍历调用list中每个元素.
import pytest
@pytest.fixture(params=[1, 2, 3])
def need_data(request): # 传入参数request 系统封装参数
return request.param # 取列表中单个值,默认的取值方式
class Test_ABC:
def test_a(self,need_data):
print("test_a 的值是 %s" % need_data)
assert need_data != 3 # 断言need_data不等于3
if __name__ == '__main__':
pytest.main("-s test_abc.py")
结果
PASSED [ 33%]
test_a 的值是 1
PASSED [ 66%]
test_a 的值是 2 [100%]--->test_1
5. 总结
使用fixture我们可以把一些重复的操作进行简化或者提前处理,来提升代码的效率.使用方式有很多要灵活使用.
6.Pytest 提高2
学习目标
- 掌握如何进行函数数据参数化
1. 跳过测试函数
使用场景: 根据特定条件、不执行标识的测试函数
方法:
skipif(condition, reason=None)
参数解释:
- condition: 跳过的条件,必传参数
- reason: 标注原因,必传参数
使用方法:
@pytest.mark.skipif(condition, reason='xxx')
代码示例
import pytest
class Test_ABC:
def setup_class(self):
print("\nsetup")
def teardown_class(self):
print("\nteardown")
def test_a(self):
print("test_a")
@pytest.mark.skipif(condition=2>1, reason="跳过")
def test_b(self):
print("test_b")
assert 0
执行结果:
collected 2 items
test_2.py
setup
test_a
.s # 代表跳过不执行
teardown
2. 标记为预期失败函数
使用场景: 标记某测试函数会失败
方法:
xfail(condition=None, reason=None, raises=None, run=True, strict=False)
常用参数:
condition:预期失败的条件,必传参数
reason:失败的原因,必传参数
使用方法:
@pytest.mark.xfail(condition, reason="xxx")
代码示例
import pytest
class Test_ABC:
def setup_class(self):
print("\nsetup")
def teardown_class(self):
print("\nteardown")
def test_a(self):
print("test_a")
@pytest.mark.xfail(condition=2>1, reason="预期失败")
def test_b(self):
print("test_b")
assert 0
# 执行结果
collected 2 items
test_2.py
setup
test_a
.test_b
x # 代表预期失败
teardown
3. 函数数据参数化
作用: 方便测试函数对测试属性的获取
方法:
parametrize(argnames, argvalues, indirect=False, ids=None, scope=None)
常用参数:
argnames:参数名
argvalues:
- 参数对应值,类型必须为list
- 当参数为一个时,参数格式:[value]
- 当参数个数大于一个时,格式为:[(param_value1,param_value2.....),(param_value1,param_value2.....)]
使用方法:
@pytest.mark.parametrize(argnames,argvalues)
⚠️ 参数值为N个,测试方法就会运行N次
示例代码
import pytest
class Test_ABC:
def setup_class(self):
print("setup")
def teardown_class(self):
print("teardown")
def test_a(self):
print("test_a")
@pytest.mark.parametrize("a", [3,6])
def test_b(self, a):
print("test data:a=%d" % a)
assert a%3 == 0
# 执行结果
test_2.py setup
test_a
.
test data:a=3
.
test data:a=6
.
teardown
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix