Pytest BDD中Fixture与Conftest问题:Feature参数无法识别
问题解决:pytest-bdd 中「fixture 'stage' not found」错误修复
错误原因
你将@pytest.fixture与@given装饰器混用在同一个函数上,导致pytest把步骤解析出来的stage、tenant参数当成pytest fixture去查找,而这两个参数是来自Gherkin特征文件的动态参数,并非预定义的fixture,因此触发找不到fixture的错误。
分步修复方案
1. 修正 conftest.py 中的认证步骤
移除http_session函数上的@pytest.fixture装饰器,改用target_fixture参数将步骤返回的会话对象转为fixture,供后续步骤复用:
import pytest import requests import json # 补充缺失的json导入 from pytest_bdd import given, parsers @pytest.fixture(scope='session') def config(): with open('config.json') as config_file: config = json.load(config_file) return config # 用target_fixture将步骤返回值转为可复用的fixture @given(parsers.parse('The user is authenticated on stage "{stage}" with tenant "{tenant}"'), target_fixture="http_session") def http_session(config, stage, tenant): login_url = f"https://{stage}/{tenant}/public/login" payload = { 'username': config['username'], 'password': config['password'] } session = requests.Session() response = session.post(login_url, data=payload, allow_redirects=True) # 新增登录成功断言,提前排查认证问题 assert response.status_code in (200, 302), f"认证失败,状态码:{response.status_code}" return session
2. 新增请求参数存储 fixture(避免测试污染)
在conftest.py中添加request_data fixture,用于存储每个测试用例的临时请求参数,避免修改全局config字典导致的测试污染:
@pytest.fixture(scope='function') def request_data(config): return { 'url': config['url'], 'http_type': None, 'headers': config['headers'] }
3. 修正 test_apis.py 中的步骤定义
替换原有的全局config修改逻辑,改用request_data存储临时参数,并修复断言错误:
from pytest_bdd import scenarios, given, when, then, parsers import pytest scenarios('../features/api.feature') @given(parsers.parse('I set the request to endpoint "{endpoint}"')) def set_endpoint(request_data, endpoint): assert len(endpoint) > 0, "endpoint参数不能为空" request_data['url'] = request_data['url'] + endpoint @when(parsers.parse('I send a HTTP "{http_type}" request')) def set_http_type(request_data, http_type): valid_methods = ('get', 'post') assert http_type.lower() in valid_methods, f"不支持的HTTP方法:{http_type}" request_data['http_type'] = http_type.lower() @then(parsers.parse('I expect http response with status code "{status_code}" and response type "{response_type}"')) def request_endpoint_statuscode(request_data, http_session, status_code, response_type): assert status_code.isdigit(), "状态码必须为数字格式" valid_types = ('json', 'xml') assert response_type.lower() in valid_types, f"不支持的响应类型:{response_type}" url = request_data['url'] http_type = request_data['http_type'] headers = request_data['headers'] # 发送请求 if http_type == 'get': response = http_session.get(url, headers=headers, allow_redirects=True) elif http_type == 'post': response = http_session.post(url, headers=headers, allow_redirects=True) else: pytest.fail(f"未实现的HTTP方法:{http_type}") # 断言状态码 assert response.status_code == int(status_code), \ f"期望状态码:{status_code},实际状态码:{response.status_code}" # 断言响应类型 assert response_type.lower() in response.headers.get('Content-Type', ''), \ f"期望响应类型:{response_type},实际Content-Type:{response.headers.get('Content-Type')}"
4. 特征文件参数替换
将api.feature中的占位符(如var_stage、var_tenant)替换为实际的环境值,例如:
Background: Given The user is authenticated on stage "dev.example.com" with tenant "test_tenant" Scenario: Basic Api request Given I set the request to endpoint "/api/v1/manuals" When I send a HTTP "get" request Then I expect http response with status code "200" and response type "json"
关键说明
- 不要混用
@pytest.fixture和@given:pytest-bdd的步骤函数参数来自Gherkin解析,并非pytest fixture,两者不能直接混用。 - 用
target_fixture实现步骤返回值复用:通过该参数可以将步骤函数的返回值转为fixture,供后续步骤依赖注入。 - 避免全局状态修改:使用独立的fixture存储测试临时参数,防止不同测试用例之间的状态污染。
内容的提问来源于stack exchange,提问作者s kop
相关产品推荐
相关产品推荐

