pytest框架常识1

@property 作用是什么?:

@property 是 Python 内置的一个装饰器,它的核心作用非常优雅:让你能把一个方法"伪装"成一个普通的属性(变量)来调用。用大白话翻译就是:去掉方法名后面的小括号 ()。

正常情况下,你读取 YAML 数据需要这样写(带括号):

python

req = RequestBase()

data = req.get_yaml_data() # 注意这里有括号

但如果你在 get_yaml_data 方法上加了 @property,调用时括号就可以省略了:

python

req = RequestBase()

data = req.get_yaml_data # 注意这里没有括号,就像访问普通属性一样

什么是钩子函数?:

"钩子函数"(Hook Function) 是理解 pytest 框架 核心机制的关键词。用一句话说人话就是:

钩子函数 = 框架预先埋好的"事件监听器"。当程序运行到特定时刻(比如刚开始、跑完一个用例、全部结束),框架会自动"触发"这些函数,让你有机会插进去执行自己的自定义代码。

接口的名字通常以 pytest_ 开头

钩子函数 = 框架给的"插口"。你只要按照 conftest.py 里规定的函数名写,不用管它什么时候运行,pytest 到了那个时间节点自动回头执行它。

@pytest.fixture(scope="session", autouse=True)这句是什么意思?:

这句话是 pytest 框架中最核心、最高频使用的配置之一。

你可以把这句装饰器理解为:"定义一个全自动、全局只执行一次的启动前保洁员"。

定义一个自动运行的初始化函数,它会在整个测试套件启动时(session)且只在一开始时(仅一次),默默地(autouse=True)把旧数据清掉、把残留报告删掉,不用每个用例单独去调用它。

1.这是 Python 的装饰器语法,它告诉 pytest:"下面这个函数不是普通的工具函数,而是一个'固件(Fixture)'。"

固件(Fixture) 在测试里的角色是:提供测试所需的前置资源或环境准备(比如:创建数据库连接、生成测试数据、清理垃圾文件)。

2.scope="session" ------ 作用范围(管多久?)

scope 参数决定了这个固件什么时候执行一次,以及执行结果能管多久。

"session" 是作用域最大的一种,意味着:在整个 pytest 测试会话中,这个固件只会在最开始执行 1 次,所有的测试用例(无论几百个)都共享这一次执行的效果。

对比其他 scope 帮你建立记忆锚点:

scope="function"(默认):每个用例执行前都跑一次(最频繁)。

scope="class":每个测试类执行前跑一次。

scope="module":每个 .py 文件执行前跑一次。

scope="session":整个测试任务(比如你运行 pytest 命令的整个过程)只跑一次。

3.autouse=True ------ 触发方式(怎么启动?)

autouse 直译是"自动使用"。

正常情况下,你想让一个固件生效,必须在测试用例的参数里写上它的名字(比如 def test_case(clear_extract):)。

加了 autouse=True 之后,你不需要在任何测试用例里去声明它。pytest 会在合适的时机(根据 scope 决定)自动、无条件地调用这个函数。

你代码里写的是 autouse=True,配合 scope="session",就变成了:"只要我一运行 pytest,不用打招呼,系统自动先把环境清理干净,且只清理这一次。"

测试用例的命名:

pytest 遍历 ./testcase 下的所有文件,把里面的 def test_xxx 函数全部找出来。这句话中test_xxx 函数一定要以test_开头吗 def test_xxx 这种写法,正是严格遵守了 pytest 对测试函数/方法的命名要求

test_xxx 函数必须以 test_ 开头,这是 pytest 框架的默认强制规则。

pytest 就是靠这个命名规则来自动发现并执行测试用例的

也可以自定义在 项目的根目录下创建一个 pytest.ini 配置文件 中自定义

@pytest.mark.parametrize 介绍:

parametrize相当于for循环遍历吗?区别很大

@pytest.mark.parametrize 是 pytest 的"用例生成器"(Generator),而不是"用例执行器"。

它的运行时机:发生在 pytest 收集用例阶段(也就是你之前问的 run.py 跳转到 pytest 内部后,正式跑代码之前)。

它的工作:把你写的 1 个函数,根据传入的列表长度,动态克隆出 N 个独立的测试函数对象

场景 A:使用 for 循环

python

def test_for_loop():

data_list = 1, 2, 3

for data in data_list:

assert data > 0 # 假设第2个数据失败了

print(f"检查完 {data}")

执行结果:当循环到 data=2 时断言失败,程序直接崩溃终止,后面的 data=3 根本不会执行,也不会被打印。

报告显示:你只会看到 1 条测试用例,状态是"失败"

场景 B:使用 @pytest.mark.parametrize(正确做法)

python

@pytest.mark.parametrize('data', 1, 2, 3)

def test_parametrize(data):

assert data > 0

print(f"检查完 {data}")

执行结果:即使 data=2 失败了,data=3 依然会继续执行。

报告显示:你会看到 3 条独立的测试用例,比如 test_parametrize1 通过,test_parametrize2 失败,test_parametrize3 通过。

你用 parametrize:pytest 会把 YAML 里的 10 条接口数据变成 10 个独立的测试用例。即使第 3 个接口报 500 错误,第 4 个接口依然会正常执行。而且在 Allure 报告里,你能清晰地看到 10 行结果,每行对应一个接口,而不是笼统的 1 行。