12 KiB
什么是行为驱动的Python?
您是否听说过行为驱动开发(BDD),并想知道所有的新奇事物是什么? 也许你已经发现了团队成员在使用“gherkin”了,并感到被排除在外无法参与其中。 或许你是一个Python爱好者,正在寻找更好的方法来测试你的代码。 无论在什么情况下,了解BDD都可以帮助您和您的团队实现更好的协作和测试自动化,而Python的行为
框架是一个很好的起点。
什么是BDD?
- 在网站上提交表单
- 搜索想要的结果
- 保存文档
- 进行REST API调用
- 运行命令行界面命令
在软件中,行为是指在明确定义的输入,行为和结果场景中功能是如何运转的。 产品可以表现出无数的行为,例如:
根据产品的行为定义产品的功能可以更容易地描述产品,并对其进行开发和测试。 BDD的核心是:使行为成为软件开发的焦点。 在开发早期使用示例语言的规范来定义行为。 最常见的行为规范语言之一是Gherkin,Cucumber项目中的Given-When-Then场景格式。 行为规范基本上是对行为如何工作的简单语言描述,具有一致性和焦点的一些正式结构。 通过将步骤文本“粘合”到代码实现,测试框架可以轻松地自动化这些行为规范。
下面是用Gherkin编写的行为规范的示例:
根据产品的行为定义产品的功能可以更容易地描述产品,开发产品并对其进行测试。 这是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
有两个主要层:
- 用Gherkin的
.feature
文件编写的行为规范 - 用Python模块编写的步骤定义和钩子,用于实现Gherkin步骤
如上例所示,Gherkin场景有三部分格式:
- 鉴于一些初始状态
- 当行为发生时
- 然后验证结果
当behave
运行测试时,每个步骤由装饰器“粘合”到Python函数。
安装
作为先决条件,请确保在你的计算机上安装了Python和pip
。 我强烈建议使用Python 3.(我还建议使用pipenv
,但以下示例命令使用更基本的pip
。)
behave
框架只需要一个包:
pip install behave
其他包也可能有用,例如:
pip install requests # 用于调用REST API
pip install selenium # 用于web浏览器交互
GitHub上的behavior-driven-Python项目包含本文中使用的示例。
Gherkin特点
behave
框架使用的Gherkin语法实际上是符合官方的Cucumber Gherkin标准的。 .feature
文件包含功能Feature部分,而Feature部分又包含具有Given-When-Then步骤的场景Scenario部分。 以下是一个例子:
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
框架忽略掉的注释。将功能描述放在那里是一种很好的做法。 - Scenarios和Features可以有标签(注意
@cucumber-basket
标记)用于钩子和过滤(如下所述)。 - 步骤都遵循严格的Given-When-Then顺序。
- 使用
And
和Bu
t可以为任何类型添加附加步骤。 - 可以使用输入对步骤进行参数化——注意双引号里的值。
通过使用场景大纲,场景也可以写为具有多个输入组合的模板:
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 |
场景大纲总是有一个Examples表,其中第一行给出列标题,后续每一行给出一个输入组合。 只要列标题出现在由尖括号括起的步骤中,行值就会被替换。 在上面的示例中,场景将运行三次,因为有三行输入组合。 场景大纲是避免重复场景的好方法。
Gherkin语言还有其他元素,但这些是主要的机制。 想了解更多信息,请阅读Automation Panda这个网站的文章Gherkin by Example和Writing Good Gherkin。
Python机制
每个Gherkin步骤必须“粘合”到步骤定义,即提供了实现的Python函数。 每个函数都有一个带有匹配字符串的步骤类型装饰器。 它还接收共享的上下文和任何步骤参数。 功能文件必须放在名为features/
的目录中,而步骤定义模块必须放在名为features/steps/
的目录中。 任何功能文件都可以使用任何模块中的步骤定义——它们不需要具有相同的名称。 下面是一个示例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
可以使用三个步骤匹配器:parse
,cfparse
和re
。默认和最简单的匹配器是parse
,如上例所示。注意如何解析参数化值并将其作为输入参数传递给函数。一个常见的最佳实践是在步骤中给参数加双引号。
每个步骤定义函数还接收一个上下文变量,该变量保存当前正在运行的场景的数据,例如feature
, scenario
和tags
字段。也可以添加自定义字段,用于在步骤之间共享数据。始终使用上下文来共享数据——永远不要使用全局变量!
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()
注意:也可以使用fixtures进行构建和清理。
要了解一个behave
项目应该是什么样子,这里是示例项目的目录结构:
任何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-bdd
,pytest
的插件,和behave
一样,它使用Gherkin功能文件和步骤定义模块,但它也利用了pytest
的所有功能和插件。例如,它可以使用pytest-xdist
并行运行Gherkin场景。 BDD和非BDD测试也可以与相同的过滤器一起执行。pytest-bdd
还提供更灵活的目录布局。radish
是一个“Gherkin增强版”框架——它将Scenario循环和前提条件添加到标准的Gherkin语言中,这使得它对程序员更友好。它还提供丰富的命令行选项,如behave
。lettuce
是一种较旧的BDD框架,与behave
非常相似,在框架机制方面存在细微差别。然而,GitHub最近显示该项目的活动很少(截至2018年5月)。
任何这些框架都是不错的选择。
另外,请记住,Python测试框架可用于任何黑盒测试,即使对于非Python产品也是如此! BDD框架非常适合Web和服务测试,因为它们的测试是声明性的,而Python是一种很好的测试自动化语言。
本文基于作者的PyCon Cleveland 2018演讲,行为驱动的Python。
via: https://opensource.com/article/18/5/behavior-driven-python
作者:Andrew Knight 选题:lujun9972 译者:Flowsnow 校对:校对者ID