从零开始学习pytest(二)
一.在命令行模式控制测试用例执行
pytest -x # 第01次失败,就停止测试
pytest --maxfail=2 # 出现2个失败就终止测试
pytest test_mod.py#指定测试模块
pytest testing/ #指定测试目录
二.pytest配置文件pytest.ini文件
#配置pytest命令行运行参数
[pytest]
addopts = -s ... # 空格分隔,可添加多个命令行参数 -所有参数均为插件包的参数配置测试搜索的路径
testpaths = ./scripts # 当前目录下的scripts文件夹 -可自定义
#配置测试搜索的文件名称
python_files = test*.py
#当前目录下的scripts文件夹下,以test开头,以.py结尾的所有文件 -可自定义
配置测试搜索的测试类名
python_classes = Test_*
#当前目录下的scripts文件夹下,以test开头,以.py结尾的所有文件中,以Test开头的类 -可自定义
配置测试搜索的测试函数名
python_functions = test_*
#当前目录下的scripts文件夹下,以test开头,以.py结尾的所有文件中,以Test开头的类内,以test_开头的方法 -可自定义
三.pytest的conftest.py文件
3.1conftest的概念和作用
在 pytest 中,conftest.py 是一个特殊的配置文件,用于定义测试的共享逻辑(如夹具 fixtures、钩子函数 hooks 和插件配置)。它允许你在多个测试文件中复用代码,而无需显式导入。
作用域:对同一文件目录及子目录下所有的测试文件生效,不同目录有自己的conftest.py文件,优先级从近到远(子目录覆盖父目录)
典型用法:1.定义全局模块的fixture(如数据库连接,模拟数据)2.添加自定义钩子(如修改测试报告,跳过特定的测试和用例)3.配置插件或命令行选项
3.2定义fixture(常用)
# conftest.py
import pytest
@pytest.fixture(scope="session")
def database_connection():
"""全局数据库连接(整个测试会话只创建一次)"""
conn = create_db_connection()
yield conn # 测试结束后关闭连接
conn.close()
@pytest.fixture
def mock_user():
"""每个测试函数独立的模拟用户数据"""
return {"id": 1, "name": "Test User"}
3.3注意事项
- 命名固定:必须命名为
conftest.py,不可修改。 - 自动发现:
pytest会自动检测并加载该文件。 - 避免循环依赖:不要在
conftest.py中导入测试文件。 - 作用域控制:
scope="session":整个测试周期执行一次。scope="module":每个测试文件执行一次。scope="function"(默认):每个测试函数执行一次。
通过conftest.py文件,可以更高效地管理测试依赖和全局配置,减少重复代码,是pytest的核心机制
四.fixture装饰器
4.1fixture是什么
在 pytest 中,conftest.py 文件中定义的 fixture 是测试框架的核心功能之一,主要用于依赖注入和测试资源的生命周期管理。
4.2fixture的参数详情
-autouse:默认为flase,若为true,则每个测试方法都会自动调用该fixture,无需传入函数名
-params: Fixture的可选形参列表,支持列表传入,默认为none,每个parame的值,fixture都会执行调用一次,类似于for循环,可与ids参数一起使用,作为每个参数的标识。测试同一功能的不同输入组合,验证边界值,异常情况。
-ids:与params一对一配合使用,一对一关系,标识测试报告中测试用例的名称。
-name:通常来说,fixture的测试函数会将fixture的函数名作为参数传递,但fixture也允许更改,如果使用了name函数,那么原来的函数名将不再生效,取而代之的是使用name的值传递。
4.3fixture的作用域
scope="function“ fixture在测试结束后被摧毁(默认)。
示例:
import pytest
@pytest.fixture(scope="function")
def loginmassage():
print("正在登录")
class Testfirst:
def test_login1(self,loginmassage):
print("A正在登录")
def test_login2(self,loginmassage):
print("B正在登录")
上述代码的fixture作用域是function,运行之后可以得到结果
============================= test session starts =============================
collecting ... collected 2 items
test_first.py::Testfirst::test_login1
test_first.py::Testfirst::test_login2
============================== 2 passed in 0.18s ==============================
正在登录
PASSED [ 50%]A正在登录
正在登录
PASSED [100%]B正在登录
Process finished with exit code 0
可见在每个函数执行前fixture都被创建,并且都在函数运行结束之后被销毁。
scope="class“ fixture在整个类的测试结束之后被摧毁。
将上述代码fixture的作用域改为class,再次运行代码,得到如下结果
============================= test session starts =============================
collecting ... collected 2 items
test_first.py::Testfirst::test_login1
test_first.py::Testfirst::test_login2
============================== 2 passed in 0.18s ==============================
正在登录
PASSED [ 50%]A正在登录
PASSED [100%]B正在登录
Process finished with exit code 0
可见fixture在整个类的运行中只创建销毁了一次。
scope="module“ fixture在整个模块的测试结束后被摧毁。
示例:
import pytest
@pytest.fixture(scope="module")
def loginmassage():
print("正在登录")
class Testfirst:
def test_login1(self,loginmassage):
print("A正在登录")
def test_login2(self,loginmassage):
print("B正在登录")
def test_logoin3(loginmassage):
print("C正在登录")
将fixture的作用域改为module,运行可得到以下结果,由此可见fixture在整个模块中只被创建销毁了一次
result:
============================= test session starts =============================
collecting ... collected 3 items
test_first.py::Testfirst::test_login1
test_first.py::Testfirst::test_login2
test_first.py::test_logoin3 正在登录
PASSED [ 33%]A正在登录
PASSED [ 66%]B正在登录
PASSED [100%]C正在登录
============================== 3 passed in 0.18s ==============================
scope="package“ fixture在整个包的测试结束后被摧毁。
scope="session“ fixture在整个测试周期执行结束后被摧毁。
浙公网安备 33010602011771号