Pytest-Bdd-Playwright 系列教程(12):步骤参数 & parsers参数解析

Pytest-Bdd-Playwright 系列教程(12):步骤参数 & parsers参数解析

  • 前言
  • 一、什么是步骤参数?
  • [二、pytest-bdd 的步骤参数用法](#二、pytest-bdd 的步骤参数用法)
    • [2.1 简单字符串解析](#2.1 简单字符串解析)
    • [2.2 自定义正则表达式解析](#2.2 自定义正则表达式解析)
    • [2.3 参数类型转换](#2.3 参数类型转换)
  • [三、案例:基于 pytest-bdd 实现计算器功能测试](#三、案例:基于 pytest-bdd 实现计算器功能测试)
    • [3.1. 编写 Feature 文件](#3.1. 编写 Feature 文件)
    • [3.2 实现步骤定义](#3.2 实现步骤定义)
    • [3.3 执行测试](#3.3 执行测试)
  • 四、最佳实践
  • 总结

前言

  • 在 pytest-bdd 中,步骤参数是构建动态、灵活测试用例的核心功能之一,它允许通过占位符的形式将具体值插入步骤中,从而避免重复编写相似的场景;
  • 我们可以通过给步骤添加参数来重用步骤,实现单一实现和多重使用,从而使代码更简洁;
  • 本文将探讨如何通过简单字符串解析、自定义正则表达式解析以及参数类型转换等方法来灵活处理不同的参数需求,并通过一个基于计算器功能的完整案例进行说明。

一、什么是步骤参数?

在 Gherkin 描述中,步骤参数(Step Parameters)是动态定义测试数据的关键方式。它允许通过占位符的形式将具体值插入步骤中,从而避免重复编写相似的场景。例如:

gherkin 复制代码
Given 第一个数字是 5
And 第二个数字是 3
When 我按下 加号
Then 结果应该是 8

上述例子中的 538 是参数,通过步骤实现函数将它们传递到测试逻辑中进行处理。

二、pytest-bdd 的步骤参数用法

在 pytest-bdd 中,步骤参数通过字符串匹配实现,配合 pytest-bdd.parsers 模块,可以实现灵活的参数解析。以下是几种常见的参数解析方式:

2.1 简单字符串解析

简单字符串解析是 pytest-bdd 的默认行为,可以直接使用占位符解析参数。例如:

gherkin 复制代码
Given 第一个数字是 <first_number>

对应的 Python 实现:

python 复制代码
from pytest_bdd import given, parsers

@given(parsers.parse("第一个数字是 {first_number:d}"))
def first_number(first_number):
    return first_number

解析规则通过 {} 语法实现,其中 :d 表示参数是整数类型。

2.2 自定义正则表达式解析

如果需要更复杂的匹配逻辑,可以使用自定义正则表达式。例如:

gherkin 复制代码
Then 计算器的宽度应该是 12.5

实现代码:

python 复制代码
@then(parsers.re(r"计算器的宽度应该是 (?P<expected_width>\d+\.\d+)"))
def check_width(expected_width):
    assert float(expected_width) == 12.5

通过 parsers.re() 定义正则表达式,可以精确控制参数提取规则。

2.3 参数类型转换

pytest-bdd 支持内置的数据类型转换,例如:

  • {name:s}:字符串
  • {value:d}:整数
  • {value:f}:浮点数

在示例中,我们可以指定参数类型:

gherkin 复制代码
Given 第一个数字是 5

对应 Python 代码:

python 复制代码
@given(parsers.parse("第一个数字是 {first_number:d}"))
def first_number(first_number):
    return first_number

测试框架会自动将参数 first_number 转换为整数。


三、案例:基于 pytest-bdd 实现计算器功能测试

接下来,我们通过一个具体的案例,展示如何在 pytest-bdd 中使用步骤参数。

3.1. 编写 Feature 文件

首先,新增 featuress/calculator_example.feature文件,定义计算器的几个功能测试场景:

gherkin 复制代码
Feature: 计算器
  一个简单的计算器,用于执行基本的算术操作。

  Background:
    Given 我已经准备好计算器

  Scenario: 检查计算器的尺寸
    Then 计算器的宽度应该是 12.5
    And 计算器的高度应该是 20.0
    And 计算器的厚度应该是 0.5

  Scenario: 打开计算器
    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 文件中为上述场景定义步骤参数:

python 复制代码
import pytest
from pytest_bdd import given, when, then, parsers, scenarios


scenarios("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_number
    elif operation == "减号":
        return first_number - second_number
    elif operation == "乘号":
        return first_number * second_number
    elif operation == "除号":
        return first_number / second_number
    else:
        raise ValueError(f"不支持的操作: {operation}")

@then(parsers.parse("结果应该是 {expected_result:d}"))
def _(result, expected_result):
    assert result == expected_result

3.3 执行测试

运行测试命令:

bash 复制代码
pytest .\tests\test_calculator_example.py

输出结果如下:

四、最佳实践

  1. 合理使用参数类型

    根据步骤的需求选择合适的数据类型解析器,确保输入值正确解析。

  2. 避免重复代码

    如果多个步骤有相似逻辑,可以使用 Python 的函数装饰器和参数化技术优化代码。

  3. 使用目标 Fixture

    利用 target_fixture 提取步骤中的数据,简化上下文传递。

  4. 测试数据分离

    将测试数据与逻辑分离(如使用 Examples 表),提高测试用例的可读性和可维护性。

总结

pytest-bdd 的步骤参数功能通过灵活的解析机制,为测试用例的动态数据支持提供了强大的工具。在本文中,我们通过对步骤参数的详尽讲解和计算器案例的实操演示,展示了如何高效使用这一功能。

相关推荐
互联网杂货铺16 小时前
几个常见的Jmeter压测问题
自动化测试·软件测试·测试工具·jmeter·职场和发展·测试用例·压力测试
爱学测试的雨果20 小时前
分布式测试插件 pytest-xdist 使用详解
分布式·pytest
测试199820 小时前
Chrome+Postman做接口测试
自动化测试·软件测试·chrome·测试工具·职场和发展·测试用例·postman
小码哥说测试2 天前
Charles简单压力测试
自动化测试·软件测试·网络协议·selenium·接口测试·压力测试·postman
钱钱钱端2 天前
软件测试工程师面试整理 —— 编程与自动化!
自动化测试·软件测试·selenium·测试工具·面试·职场和发展
钱钱钱端2 天前
技术分享 —— JMeter接口与性能测试实战!
自动化测试·软件测试·python·jmeter·职场和发展·压力测试·性能测试
七灵微2 天前
【测试】Pytest
pytest
钱钱钱端3 天前
Pytest参数详解 — 基于命令行模式!
自动化测试·软件测试·python·jmeter·职场和发展·pytest·压力测试
测试19983 天前
什么是自动化测试?
自动化测试·软件测试·python·测试工具·程序人生·职场和发展·测试用例
虹科网络安全4 天前
艾体宝案例丨CircleCI 助力 ANA Systems 打造高效 CI/CD 模型
自动化测试·ci/cd·持续集成·saas平台·circleci