一、定义
在Python的pytest
测试框架中,@pytest.fixture
是一个(不是唯一)装饰器,用于定义一个测试夹具。
二、简单实例
使用参数autouser=True
@pytest.fixture(autouse=True)
def my_fixture():print("Setup: 准备测试环境")yieldprint("Teardown: 清理测试环境")def test_example():print("Running: 测试函数")
执行结果
使用参数name
@pytest.fixture(name="test")def my_fixture(self):print("Setup: 准备测试环境")yieldprint("Teardown: 清理测试环境")def test_example(self,test):print("测试函数")
执行结果
使用参数params和ids
在 pytest
中,ids
通常与 params
参数一起使用,以便为每个参数化测试提供标识符。params
提供了参数化的值,而 ids
为这些值提供了可读的标识符
class TestWebsite:@pytest.fixture(name="test", params=["a", "b", "c"], ids=["id_a", "id_b", "id_c"])def my_fixture(self, request):print(f"准备测试环境,使用参数 {request.param}")yield request.paramprint("清理测试环境")def test_example(self, test):print(f"测试函数,使用的参数是 {test}")
执行结果
使用scope
function
函数级别,默认值。每个测试函数都会调用一次夹具
class TestWebsite:@pytest.fixture(autouse=True, scope="function")def my_fixture(self):print(f"准备测试环境")yieldprint("清理测试环境")def test_example1(self):print(f"测试函数")def test_example2(self):print(f"测试函数")
执行结果
class
类级别。夹具的设置代码在第一个测试方法执行前运行一次,清理代码在最后一个测试方法执行后运行一次
@pytest.fixture(autouse=True, scope="class")
def my_fixture():print(f"准备测试环境")yieldprint("清理测试环境")class TestA:def test_example1(self):print(f"测试函数")def test_example2(self):print(f"测试函数")class TestB:def test_example1(self):print(f"测试函数")def test_example2(self):print(f"测试函数")
运行结果
module
模块级别。夹具在同一个模块中的所有测试函数之间共享
@pytest.fixture(autouse=True, scope="module")
def my_fixture():print(f"准备测试环境")yieldprint("清理测试环境")class TestA:def test_example1(self):print(f"测试函数")def test_example2(self):print(f"测试函数")class TestB:def test_example1(self):print(f"测试函数")def test_example2(self):print(f"测试函数")
运行结果
session
会话级别。整个测试会话中只创建一次夹具示例
演示该参数需要两个Python文件。
test_1
@pytest.fixture(autouse=True, scope="session")
def my_fixture():print(f"\nsession准备测试环境")yieldprint("session清理测试环境")class TestA:def test_example1(self):print(f"测试函数session")
test_2
@pytest.fixture(autouse=True, scope="module")
def my_fixture():print(f"\nmodule准备测试环境")yieldprint("module清理测试环境")class TestA:def test_example1(self):print(f"测试函数module")
运行结果
可以看到module级别的作用域只能在当前模块生效,而session级别的作用域,在整个会话都生效
package
包级别。这个作用域在 pytest
3.5 版本中引入,用于跨越多个模块和会话共享夹具实例,需要导入夹具。
这里使用两个不同的模块演示。
test_1
#!/usr/bin/env python
# -*- coding: utf-8 -*-import pytest@pytest.fixture(scope="package")
def package_fixture():print(f"\n准备测试环境")yieldprint("清理测试环境")def test_example1(package_fixture):print(f"测试函数test_1")
test_2
#!/usr/bin/env python
# -*- coding: utf-8 -*-import pytest
from .test_1 import package_fixturedef test_example1(package_fixture):print(f"测试函数test_2")
运行结果
三、源码解读
注释解读:对照行
纯中文
标记一个夹具工厂函数的装饰器。这个装饰器可以用来定义一个夹具函数,无论是否带有参数。稍后可以通过引用夹具函数的名称来调用它:测试模块或类可以使用 ``pytest.mark.usefixtures(fixturename)`` 标记。测试函数可以直接使用夹具名称作为输入参数,在这种情况下,从夹具函数返回的夹具实例将被注入。夹具可以通过 ``return`` 或 ``yield`` 语句向测试函数提供它们的值。当使用 ``yield`` 时,``yield`` 语句后的代码块将作为清理代码执行,无论测试结果如何,并必须恰好产生一次。:param scope:这个夹具共享的范围;可以是 ``"function"``(默认)、``"class"``、``"module"``、``"package"`` 或 ``"session"`` 之一。这个参数也可以是一个可调用的,它接收 ``(fixture_name, config)`` 作为参数,并必须返回上述值之一的 ``str``。有关更多信息,请参见文档中的 :ref:`dynamic scope`。:param params:一个可选的参数列表,它将导致夹具函数的多次调用以及所有使用它的测试。当前的参数可以在 ``request.param`` 中获取。:param autouse:如果为 True,则对于可以看到它的所有测试,夹具函数将被激活。如果为 False(默认值),需要显式引用才能激活夹具。:param ids:每个参数对应的一组 ID,以便它们是测试 ID 的一部分。如果没有提供 ids,它们将根据参数自动生成。:param name:夹具的名称。这默认为装饰函数的名称。如果夹具在定义它的模块中使用,夹具的函数名称将被请求夹具的函数参数遮蔽;解决这个问题的一个方法是将装饰函数命名为 ``fixture_<fixturename>``,然后使用 ``@pytest.fixture(name='<fixturename>')``。