Pytest-Bdd-Playwright 系列教程(12):步骤参数 & parsers参数解析
前言
一、什么是步骤参数?
在 Gherkin 描述中,步骤参数(Step Parameters)是动态定义测试数据的关键方式。它允许通过占位符的形式将具体值插入步骤中,从而避免重复编写相似的场景。例如:
Given 第一个数字是 5
And 第二个数字是 3
When 我按下 加号
Then 结果应该是 8
上述例子中的 5
、3
和 8
是参数,通过步骤实现函数将它们传递到测试逻辑中进行处理。
pytestbdd__21">二、pytest-bdd 的步骤参数用法
在 pytest-bdd 中,步骤参数通过字符串匹配实现,配合 pytest-bdd.parsers
模块,可以实现灵活的参数解析。以下是几种常见的参数解析方式:
2.1 简单字符串解析
简单字符串解析是 pytest-bdd 的默认行为,可以直接使用占位符解析参数。例如:
Given 第一个数字是 <first_number>
对应的 Python 实现:
from pytest_bdd import given, parsers@given(parsers.parse("第一个数字是 {first_number:d}"))
def first_number(first_number):return first_number
解析规则通过 {}
语法实现,其中 :d
表示参数是整数类型。
2.2 自定义正则表达式解析
如果需要更复杂的匹配逻辑,可以使用自定义正则表达式。例如:
Then 计算器的宽度应该是 12.5
实现代码:
@then(parsers.re(r"计算器的宽度应该是 (?P<expected_width>\d+\.\d+)"))
def check_width(expected_width):assert float(expected_width) == 12.5
通过 parsers.re()
定义正则表达式,可以精确控制参数提取规则。
2.3 参数类型转换
{name:s}
:字符串{value:d}
:整数{value:f}
:浮点数
在示例中,我们可以指定参数类型:
Given 第一个数字是 5
对应 Python 代码:
@given(parsers.parse("第一个数字是 {first_number:d}"))
def first_number(first_number):return first_number
测试框架会自动将参数 first_number
转换为整数。
pytestbdd__89">三、案例:基于 pytest-bdd 实现计算器功能测试
接下来,我们通过一个具体的案例,展示如何在 pytest-bdd 中使用步骤参数。
3.1. 编写 Feature 文件
首先,新增 featuress/calculator_example.feature
文件,定义计算器的几个功能测试场景:
Feature: 计算器一个简单的计算器,用于执行基本的算术操作。Background:Given 我已经准备好计算器Scenario: 检查计算器的尺寸Then 计算器的宽度应该是 12.5And 计算器的高度应该是 20.0And 计算器的厚度应该是 0.5Scenario: 打开计算器Given 我按下电源按钮Then 屏幕应该亮起Scenario Outline: 两个数之间的计算Given 我检查按钮是否正常And 第一个数字是 <first_number>And 第二个数字是 <second_number>When 我按下 <operation>Then 结果应该是 <expected_result>Examples:| first_number | second_number | operation | expected_result || 5 | 3 | 加号 | 8 || 10 | 4 | 减号 | 6 || 2 | 6 | 乘号 | 12 || 8 | 2 | 除号 | 4 |
3.2 实现步骤定义
在 tests/test_calculator_example.py
文件中为上述场景定义步骤参数:
import pytest
from pytest_bdd import given, when, then, parsers, scenariosscenarios("calculator_example.feature")@given("我已经准备好计算器")
def _():print("计算器已准备好!")@given("我检查按钮是否正常")
def _():print("按钮已检查。")@given("我按下电源按钮")
def _():pass@then("屏幕应该亮起")
def _():pass@then(parsers.parse("计算器的宽度应该是 {expected_width:f}"))
def _(expected_width: float):print(f"宽度: {expected_width}")@then(parsers.parse("计算器的高度应该是 {expected_height:f}"))
def _(expected_height: float):print(f"高度: {expected_height}")@then(parsers.parse("计算器的厚度应该是 {expected_thickness:f}"))
def _(expected_thickness: float):print(f"厚度: {expected_thickness}")@given(parsers.parse("第一个数字是 {first_number:d}"), target_fixture="first_number")
def _(first_number):return first_number@given(parsers.parse("第二个数字是 {second_number:d}"), target_fixture="second_number")
def _(second_number):return second_number@when(parsers.parse("我按下 {operation}"), target_fixture="result")
def _(operation, first_number, second_number):if operation == "加号":return first_number + second_numberelif operation == "减号":return first_number - second_numberelif operation == "乘号":return first_number * second_numberelif operation == "除号":return first_number / second_numberelse:raise ValueError(f"不支持的操作: {operation}")@then(parsers.parse("结果应该是 {expected_result:d}"))
def _(result, expected_result):assert result == expected_result
3.3 执行测试
运行测试命令:
pytest .\tests\test_calculator_example.py
输出结果如下:
四、最佳实践
-
合理使用参数类型
根据步骤的需求选择合适的数据类型解析器,确保输入值正确解析。 -
避免重复代码
如果多个步骤有相似逻辑,可以使用 Python 的函数装饰器和参数化技术优化代码。 -
使用目标 Fixture
利用target_fixture
提取步骤中的数据,简化上下文传递。 -
测试数据分离
将测试数据与逻辑分离(如使用 Examples 表),提高测试用例的可读性和可维护性。
总结
pytest-bdd 的步骤参数功能通过灵活的解析机制,为测试用例的动态数据支持提供了强大的工具。在本文中,我们通过对步骤参数的详尽讲解和计算器案例的实操演示,展示了如何高效使用这一功能。