我不知道为什么将 此处提到的代码 修改为以下内容不起作用?这些变量在测试内部不可访问,并且尽管范围设置为类,但在每次测试之前都会调用设置。任何指示都会非常有帮助。谢谢
#conftest.py
def pytest_addoption(parser):
parser.addoption("--data", action="store", default="1,2 3,4 5,6", help="Data for parametrization")
def pytest_generate_tests(metafunc):
data_str = metafunc.config.getoption("data")
# data_list = [(1, 2), (3, 4), (5, 6)]
data_list = [tuple(map(int, item.split(','))) for item in data_str.split()]
# metafunc.parametrize("data", data_list, indirect=True)
metafunc.parametrize("data", data_list, scope="class")
# @pytest.fixture(scope="class")
# def data(request):
# return request.param
#test_code.py
import pytest
class Test1():
@pytest.fixture(scope="class", autouse=True)
def setup(self, data, request):
print(data)
[self.a, self.b] = list(data)
self.c = self.a + self.b
print('Test1.setup')
def test_a(self):
print("Test1.test_a")
print(f'Test1.test_a - {self.a}, {self.b}, {self.c}')
self.d = self.c * 2
def test_b(self):
print("Test1.test_b")
print(f'Test1.test_b - {self.d}')
代码无法按预期工作的原因是,试图将
scope="class"
与
pytest_generate_tests
中的参数化以及
autouse=True
与
setup
fixture 中的参数结合使用。这种组合在 pytest 中不起作用。
以下是发生的事情以及如何修复它:
-
pytest_generate_tests
中的参数化 :当使用metafunc.parametrize("data", data_list, scope="class")
时,pytest 会为data_list
中的每个元素创建一个Test1
类的 实例 。这意味着setup
fixture 和其中的所有内容(包括self.a
、self.b
和self.c
)都会为每个测试用例 单独实例化 。 -
autouse=True
:setup
fixture 上的autouse=True
意味着它将在每个测试函数 之前 自动运行,而无需在测试函数中明确请求它。 -
组合问题 :由于将
scope="class"
与pytest_generate_tests
中的参数化一起使用,因此setup
fixture 会在Test1
类的每个 实例 上运行,该实例是在为data_list
中的每个值创建的。这意味着self.a
、self.b
和self.c
会在每个测试用例之前被覆盖,从而导致意外行为。
解决方案
为了解决此问题,可以将参数化移动到类级别,并使用
pytest.mark.parametrize
装饰器:
# conftest.py
def pytest_addoption(parser):
parser.addoption("--data", action="store", default="1,2 3,4 5,6", help="Data for parametrization")
def pytest_generate_tests(metafunc):
if 'data' in metafunc.fixturenames:
data_str = metafunc.config.getoption("data")
data_list = [tuple(map(int, item.split(','))) for item in data_str.split()]
metafunc.parametrize("data", data_list, scope="class")
# test_code.py
import pytest
@pytest.mark.parametrize("data", [(1, 2), (3, 4), (5, 6)], scope="class")
class Test1():
@pytest.fixture(scope="class", autouse=True)
def setup(self, request):
self.a, self.b = request.param
self.c = self.a + self.b
print('Test1.setup')
def test_a(self):
print("Test1.test_a")
print(f'Test1.test_a - {self.a}, {self.b}, {self.c}')
self.d = self.c * 2
def test_b(self):
print("Test1.test_b")
print(f'Test1.test_b - {self.d}')
在此解决方案中:
-
我们使用
@pytest.mark.parametrize
装饰器在类级别应用参数化。 -
setup
fixture 现在正确地获取了request.param
中的参数化数据,并为每个测试用例设置了类属性。
这将确保
setup
fixture 仅运行
一次
,并且
self.a
、
self.b
和
self.c
的值在
Test1
类的所有测试用例中都可用。