pytest框架---fixture固件

在 Pytest 框架中,Fixture(固件) 绝对是最核心、最强大的功能,没有之一。如果说 parametrize 是 Pytest 的"心脏"(负责驱动数据),那么 Fixture 就是 Pytest 的"神经系统"(负责提供测试所需的全部外部资源和环境)。

python 复制代码
@pytest.fixture
def login_token():
    print("① 去数据库查用户,生成 token")  # 前置
    yield "abc123"                         # 把 token 交给用例
    print("③ 用例跑完了,删除这个 token 缓存") # 后置(无论用例成功还是失败,都会执行!)

def test_order(login_token):
    print("② 拿着 token 下单")
    assert "abc123" in login_token

上面这段代码的打印顺序是:① → ② → ③

把 yield 换成 return 的执行顺序:① → ②(③ 永远不会执行)

Pytest 的执行指针(Instruction Pointer)跳转顺序:

第 0 步(准备):Pytest 扫描发现 test_order 需要 login_token 参数,决定先去 login_token 拿值。

指针跳转到第 ② 行:Pytest 调用 login_token() 函数。

指针进入第 ③ 行:执行 print("① ...")(此时控制台输出 ①)。

指针到达第 ④ 行:遇到 yield "abc123",函数在此处暂停(冻结),把 "abc123" 扔出来。

指针跳出 login_token:Pytest 拿到了返回值。

指针跳转到第 ⑥ 行:Pytest 拿着 "abc123",现在才开始调用 test_order()!

指针进入第 ⑦ 行:执行 print("② ...")(控制台输出 ②)。

指针进入第 ⑧ 行:执行断言。

test_order 执行完毕:Pytest 发现调用结束了。

指针再次跳回第 ④ 行(yield 的下一行):Pytest 恢复之前暂停的 login_token 函数,执行第 ⑤ 行 print("③ ...")(控制台输出 ③)。

上面代码中assert "abc123" in login_token 这句代码 还会再调用一遍login_token函数吗

绝对不会! 这句断言 不会再调用一遍 login_token 函数

  1. 执行时的真相(变量与函数的区别)
    在 def test_order(login_token): 这一行中,login_token 是函数的形参(参数名)。
    当 Pytest 要运行这个测试时,它做的事情是:
    提前执行 Fixture:它先跑去执行 login_token 这个函数,拿到返回值 "abc123"(如果在 yield 情况下,执行到 yield 暂停)。
    参数注入(赋值):Pytest 把拿到的结果 "abc123" 直接赋值给 test_order 的参数 login_token。
    执行用例:此时在函数体内,login_token 已经不再是一个函数,而是一个实实在在的字符串变量,它的值就是 "abc123"。
    所以,你在断言里写 assert "abc123" in login_token,在 Python 看来,这行代码实际上等价于assert "abc123" in "abc123"
    @pytest.fixture 上面代码中这一段代码是什么作用
    如果你把 @pytest.fixture 这行删掉 会报错。 Python 会认为 test_order 是一个普通函数,需要调用者手动传参。但你在调用时没传,所以报错。
    加上 @pytest.fixture 后:Pytest 在启动时会扫描所有被这个装饰器标记的函数,把它们记录在一个"内部字典(注册表)"里。当它看到 test_order 需要一个名为 login_token 的参数时,就会去注册表里找,找到后自动执行该函数,把返回值注入进来。这就实现了"依赖注入(DI)"------你不需要手动调用,框架帮你把"原料"送到手上。
    @pytest.fixture 是 Pytest 依赖注入的核心实现。它在框架启动时将被装饰函数注册为资源提供者,通过参数名匹配的方式,在测试函数执行前自动调用该函数获取资源(如 session、数据库连接),并支持通过 yield 实现资源的前置分配与后置回收,从而解决了测试环境的初始化和清理问题。
    被 @pytest.fixture 装饰的是 login_token 函数,而不是 test_order 函数。
    test_order 被称为"测试用例(Test Case)"或"测试函数(Test Function)"。
    核心原理:
    Pytest 在启动时(收集阶段)做了一件极其重要的事:它遍历所有以 test_ 开头的函数,把它们从"普通函数"注册进自己的"待执行队列"中,并打上"测试用例"的标签。
    当 Pytest 准备执行 test_order 时,它会检查这个函数需要哪些参数(这里需要 login_token)。Pytest 去自己的"注册表"里找,发现 login_token 是一个被 @pytest.fixture 标记的"供应商"。
    装饰器是什么?
    装饰器(Decorator) @pytest.fixture
    被装饰的函数 def login_token():
    消费者 def test_order(login_token):