什么是行为驱动的 Python?

使用 Python 的 'behave' 框架进行行为驱动开发可以帮助您的团队实现更好的协作和测试自动化。
245 位读者喜欢这篇文章。
a checklist for a team

Opensource.com

您是否听说过 行为驱动开发 (BDD) 并想知道它为何如此热门?也许您听到团队成员在谈论 “gherkin” 并感到被排除在外。或者,也许您是一名 Pythonista,正在寻找更好的代码测试方法。无论情况如何,了解 BDD 都可以帮助您和您的团队实现更好的协作和测试自动化,而 Python 的 behave 框架是一个很好的起点。

什么是 BDD?

在软件中,行为 是指功能在明确定义的输入、操作和结果场景中如何运作。产品可以展现无数种行为,例如

  • 在网站上提交表单
  • 搜索所需结果
  • 保存文档
  • 发出 REST API 调用
  • 运行命令行界面命令

基于产品的行为定义其功能,使其更容易描述、开发和测试。这是 BDD 的核心:使行为成为软件开发的焦点。行为在开发的早期阶段使用 示例规范 语言进行定义。最常见的行为规范语言之一是 Gherkin,即来自 Cucumber 项目的 Given-When-Then 场景格式。行为规范基本上是用通俗易懂的语言描述行为如何工作,并带有一些形式化的结构以保持一致性和重点。测试框架可以通过将步骤文本 “粘合” 到代码实现来轻松地自动化这些行为规范。

以下是以 Gherkin 编写的行为规范示例

Scenario: Basic DuckDuckGo Search
  Given the DuckDuckGo home page is displayed
  When the user searches for "panda"
  Then results are shown for "panda"

只需快速浏览一下,就能直观地理解该行为。除了几个关键字外,该语言是自由形式的。场景简洁但意义明确。真实世界的例子说明了该行为。步骤声明式地指示应该发生什么——而不会陷入如何实现的细节。

BDD 的主要优势 是良好的协作和自动化。每个人都可以为行为开发做出贡献,而不仅仅是程序员。从流程一开始就定义和理解预期的行为。测试可以与它们所涵盖的功能一起自动化。每个测试都涵盖一个单一的、独特的行为,以避免重复。最后,现有步骤可以被新的行为规范重用,从而产生滚雪球效应。

Python 的 behave 框架

behave 是 Python 中最流行的 BDD 框架之一。它与其他基于 Gherkin 的 Cucumber 框架非常相似,尽管它没有获得官方的 Cucumber 认证。behave 有两个主要层

  1. 以 Gherkin .feature 文件编写的行为规范
  2. 以 Python 模块编写的步骤定义和钩子,用于实现 Gherkin 步骤

如上面的示例所示,Gherkin 场景使用三部分格式

  1. 给定一些初始状态
  2. 当采取某个操作时
  3. 然后验证结果

behave 运行测试时,每个步骤都通过装饰器 “粘合” 到一个 Python 函数。

安装

作为前提条件,请确保您的机器上安装了 Python 和 pip。我强烈建议使用 Python 3。(我也建议使用 pipenv,但以下示例命令使用更基础的 pip。)

behave 只需要一个包

pip install behave

其他包也可能有用,例如

pip install requests    # for REST API calls
pip install selenium    # for Web browser interactions

GitHub 上的 behavior-driven-Python 项目包含本文中使用的示例。

Gherkin 功能

behave 使用的 Gherkin 语法实际上符合官方的 Cucumber Gherkin 标准。一个 .feature 文件包含 Feature 部分,而 Feature 部分又包含 Scenario 部分,其中包含 Given-When-Then 步骤。以下是一个示例

Feature: Cucumber Basket
  As a gardener,
  I want to carry many cucumbers in a basket,
  So that I don’t drop them all.
  
  @cucumber-basket
  Scenario: Add and remove cucumbers
    Given the basket is empty
    When "4" cucumbers are added to the basket
    And "6" more cucumbers are added to the basket
    But "3" cucumbers are removed from the basket
    Then the basket contains "7" cucumbers

这里有几个重要事项需要注意

  • Feature 和 Scenario 部分都有 简短、描述性的标题
  • 紧跟 Feature 标题的行是 behave 忽略的注释。最好将用户故事放在那里。
  • 场景和功能可以有标签(注意 @cucumber-basket 标记),用于钩子和过滤(如下所述)。
  • 步骤遵循 严格的 Given-When-Then 顺序
  • 可以使用 AndBut 为任何类型添加其他步骤。
  • 步骤可以使用输入参数化——注意双引号中的值。

场景也可以通过使用 Scenario Outline 以多个输入组合形式编写为模板

Feature: Cucumber Basket

  @cucumber-basket
  Scenario Outline: Add cucumbers
    Given the basket has “<initial>” cucumbers
    When "<more>" cucumbers are added to the basket
    Then the basket contains "<total>" cucumbers

    Examples: Cucumber Counts
      | initial | more | total |
      |    0    |   1  |   1   |
      |    1    |   2  |   3   |
      |    5    |   4  |   9   |

Scenario Outline 始终有一个 Examples 表格,其中第一行给出列标题,随后的每一行给出输入组合。行值将替换步骤中由尖括号包围的列标题出现的位置。在上面的示例中,由于有三行输入组合,因此场景将运行三次。Scenario Outline 是避免重复场景的好方法。

Gherkin 语言还有其他元素,但这些是主要机制。要了解更多信息,请阅读 Automation Panda 文章 Gherkin 示例编写好的 Gherkin

Python 机制

每个 Gherkin 步骤都必须 “粘合” 到步骤定义,即提供实现的 Python 函数。每个函数都有一个步骤类型装饰器,其中包含匹配的字符串。它还接收共享上下文和任何步骤参数。Feature 文件必须放在名为 features/ 的目录中,而步骤定义模块必须放在名为 features/steps/ 的目录中。任何 Feature 文件都可以使用来自任何模块的步骤定义——它们不需要具有相同的名称。以下是一个示例 Python 模块,其中包含 cucumber basket 功能的步骤定义。

from behave import *
from cucumbers.basket import CucumberBasket

@given('the basket has "{initial:d}" cucumbers')
def step_impl(context, initial):
    context.basket = CucumberBasket(initial_count=initial)

@when('"{some:d}" cucumbers are added to the basket')
def step_impl(context, some):
    context.basket.add(some)

@then('the basket contains "{total:d}" cucumbers')
def step_impl(context, total):
    assert context.basket.count == total

有三种 步骤匹配器 可用:parsecfparsere。默认且最简单的匹配器是 parse,如上面的示例所示。请注意,参数化的值是如何被解析并作为输入参数传递到函数中的。一个常见的最佳实践是将步骤中的参数用双引号括起来。

每个步骤定义函数还接收一个 context 变量,该变量保存特定于当前正在运行的场景的数据,例如 featurescenariotags 字段。也可以添加自定义字段,以便在步骤之间共享数据。始终使用上下文来共享数据——永远不要使用全局变量!

behave 还支持 钩子,以处理 Gherkin 步骤之外的自动化问题。钩子是一个函数,它将在步骤、场景、功能或整个测试套件之前或之后运行。钩子让人联想到 面向切面编程。它们应该放在 features/ 目录下的特殊 environment.py 文件中。钩子函数也可以检查当前场景的标签,以便有选择地应用逻辑。下面的示例演示了如何使用钩子为标记为 @web 的任何场景设置和拆卸 Selenium WebDriver 实例。

from selenium import webdriver

def before_scenario(context, scenario):
    if 'web' in context.tags:
        context.browser = webdriver.Firefox()
        context.browser.implicitly_wait(10)

def after_scenario(context, scenario):
    if 'web' in context.tags:
        context.browser.quit()

注意:设置和清理也可以使用 behave 中的 fixtures 完成。

为了让您了解 behave 项目应该是什么样子,以下是示例项目的目录结构

Example project's directory layout

任何 Python 包和自定义模块都可以与 behave 一起使用。使用良好的设计模式来构建可扩展的测试自动化解决方案。步骤定义代码应简洁明了。

运行测试

要从命令行运行测试,请更改到项目的根目录并运行 behave 命令。使用 –help 选项查看所有可用选项。

以下是一些常见的用例

# run all tests
behave

# run the scenarios in a feature file
behave features/web.feature

# run all tests that have the @duckduckgo tag
behave --tags @duckduckgo

# run all tests that do not have the @unit tag
behave --tags ~@unit

# run all tests that have @basket and either @add or @remove
behave --tags @basket --tags @add,@remove

为方便起见,选项可以保存在 config 文件中。

其他选项

behave 不是 Python 中唯一的 BDD 测试框架。其他优秀的框架包括

  • pytest-bddpytest 的插件。与 behave 类似,它使用 Gherkin 功能文件和步骤定义模块,但它也利用了 pytest 的所有功能和插件。例如,它可以使用 pytest-xdist 并行运行 Gherkin 场景。BDD 和非 BDD 测试也可以使用相同的过滤器一起执行。pytest-bdd 还提供了更灵活的目录布局。
  • radish 是一个 “Gherkin-plus” 框架——它向标准 Gherkin 语言添加了 Scenario Loops 和 Preconditions,这使其对程序员更加友好。它还提供了像 behave 一样丰富的命令行选项。
  • lettuce 是一个较旧的 BDD 框架,与 behave 非常相似,框架机制略有不同。但是,GitHub 显示该项目最近活动很少(截至 2018 年 5 月)。

这些框架中的任何一个都是不错的选择。

另请记住,Python 测试框架可以用于任何黑盒测试,即使对于非 Python 产品也是如此!BDD 框架非常适合 Web 和服务测试,因为它们的测试是声明式的,而 Python 是 测试自动化的绝佳语言


本文基于作者在 PyCon Cleveland 2018 上的演讲 行为驱动的 Python

Pandy Knight
Andrew Knight,又名 “Pandy”,是 Automation Panda。他是一位软件质量倡导者,热衷于帮助人们构建更高质量的软件。目前,作为 Applitools 的开发者布道师,Pandy 帮助人们最大限度地发挥其测试自动化的价值。

评论已关闭。

© . All rights reserved.