pytest-bdd中YAML数据加载时步骤定义未找到的原因排查
pytest-bdd Scenario Outline 出现 StepDefinitionNotFoundError 的原因及解决方法
错误根源
问题核心是Feature文件中的步骤文本与步骤定义的装饰器文本不匹配:
- Feature里的When步骤写了:
When I enter my login and "<password>",参数被双引号包裹 - 当Scenario Outline替换Examples中的参数后,实际执行的步骤文本变成了:
I enter my login and "PASSWORD1" - 但你的步骤定义装饰器是:
@when('I enter my login and <password>'),没有包含双引号,导致pytest-bdd无法找到对应的步骤实现。
解决方法
两种可行修正方式,选其一即可:
方式一:修改Feature文件,移除参数的双引号
将Feature中的When步骤改为:
When I enter my login and <password>
方式二:修改步骤定义的装饰器,匹配双引号
将@when装饰器的文本改为包含双引号的版本:
@when('I enter my login and "<password>"') def step_when_enter_credentials(webdriver_initializer, password): driver = webdriver_initializer selenium_elements = Page(driver) globals_instance = Globals(PARAMS_PATH) password_to_use = globals_instance.get_yaml_element(password) selenium_elements.type_into(selenium_elements.EMAIL_ADDRESS_REGISTER_VALUE, selenium_elements.globals.EMAIL1) selenium_elements.type_into(selenium_elements.EMAIL_PASSWORD, password_to_use)
额外优化建议
每次在步骤里实例化Globals(PARAMS_PATH)会重复加载YAML文件,建议把Globals做成pytest fixture提升执行效率:
import pytest import yaml @pytest.fixture(scope="session") def globals_fixture(): class Globals: def __init__(self, path): self.load_data_from_yaml(path) def load_data_from_yaml(self, path): with open(path, "r") as param_file: try: yaml_file = yaml.safe_load(param_file) self.TITLE = yaml_file.get("title1") self.USERNAME1 = yaml_file.get("username1") self.PASSWORD1 = yaml_file.get("password1") self.WRONG_PASSWORD = yaml_file.get("wrong_password") self.LAST_NAME1 = yaml_file.get("lastname1") self.EMAIL1 = yaml_file.get("email1") self.BDAY = yaml_file.get("bday") self.BMONTH = yaml_file.get("bmonth") self.BYEAR = yaml_file.get("byear") except yaml.YAMLError as exc: print(exc) def get_yaml_element(self, element): return getattr(self, element, None) return Globals(PARAMS_PATH)
之后在步骤里直接使用该fixture:
@when('I enter my login and <password>') def step_when_enter_credentials(webdriver_initializer, password, globals_fixture): driver = webdriver_initializer selenium_elements = Page(driver) password_to_use = globals_fixture.get_yaml_element(password) selenium_elements.type_into(selenium_elements.EMAIL_ADDRESS_REGISTER_VALUE, globals_fixture.EMAIL1) selenium_elements.type_into(selenium_elements.EMAIL_PASSWORD, password_to_use)
内容的提问来源于stack exchange,提问作者Bart77
相关产品推荐
相关产品推荐

