如何将Fixture产出数据用于Pytest测试用例参数化?求解决方案
问题背景
需要通过HTTP请求创建多个测试用户,并用这些用户的登录名、密码数据执行登录页面测试。现有实现是写了一个scope="session"且autouse=True的Fixture(test_user_fixture),该Fixture负责生成用户数据、发送请求创建用户,通过yield产出[(login1,password1), (login2,password2)]格式的元组列表,同时在测试结束后清理测试数据。
尝试在测试类TestPositiveLogin的test_positive_login方法中,直接将test_user_fixture作为@pytest.mark.parametrize的参数源,触发错误:NameError: name 'test_user_fixture' is not defined。
错误原因
@pytest.mark.parametrize是在测试用例收集阶段执行的,这个阶段pytest还没有实例化任何Fixture;而Fixture的初始化、数据生成逻辑是在测试运行阶段才执行的。所以收集阶段找不到test_user_fixture这个变量,自然抛出NameError。另外autouse=True只是让Fixture自动运行,无法直接将其产出的数据作为参数化的数据源。
可行解决方案
方案一:抽离用户数据生成逻辑,复用逻辑实现参数化+Fixture清理
把生成用户数据、创建用户的逻辑抽成独立函数,让@pytest.mark.parametrize直接调用这个函数获取参数数据;同时让原Fixture依赖这个函数,负责测试后的清理工作。这样既满足参数化需求,又能保证测试数据的清理。
修改后的代码如下:
conftest.py
import pytest def generate_and_create_test_users(): print("INFO | Generating test user data") user_data_set = user_data_generator() login_data = [] for user_data in user_data_set: login_data.append((user_data[0], user_data[1])) if send_user_create_request(user_data) != 200: pytest.exit("ERROR | Test user wasn't created") return login_data @pytest.fixture(scope="session", autouse=True) def test_user_cleanup(): # 先创建用户(复用上面的函数) generate_and_create_test_users() yield print("INFO | Clearing test data") # 这里添加清理用户的逻辑,比如发送删除请求 # cleanup_test_users()
test_login_page.py
import pytest from conftest import generate_and_create_test_users @pytest.mark.usefixtures('webdriver_fixture') class TestPositiveLogin: @pytest.mark.parametrize("login, password", generate_and_create_test_users()) def test_positive_login(self, webdriver_fixture, login, password): driver = webdriver_fixture page = BasePage(driver) page.open_base_page() page.login(login, password)
方案二:使用pytest-lazy-fixture插件延迟获取Fixture数据
如果允许安装第三方插件,可以用pytest-lazy-fixture让parametrize延迟到测试运行阶段再获取Fixture的值,避开收集阶段的限制。
- 先安装插件:
pip install pytest-lazy-fixture
- 修改代码:
conftest.py(保留原Fixture,去掉autouse=True,因为不需要自动运行)
import pytest @pytest.fixture(scope="session") def test_user_fixture(): print("INFO | Generating test user data") user_data_set = user_data_generator() login_data = [] for user_data in user_data_set: login_data.append((user_data[0], user_data[1])) if send_user_create_request(user_data) != 200: pytest.exit("ERROR | Test user wasn't created") yield login_data print("INFO | Clearing test data") # 添加清理逻辑
test_login_page.py
import pytest from pytest_lazyfixture import lazy_fixture @pytest.mark.usefixtures('webdriver_fixture') class TestPositiveLogin: @pytest.mark.parametrize("login, password", lazy_fixture("test_user_fixture")) def test_positive_login(self, webdriver_fixture, login, password): driver = webdriver_fixture page = BasePage(driver) page.open_base_page() page.login(login, password)
内容的提问来源于stack exchange,提问作者ReGuardian

