pytest-bdd
和behave
是 Python 的两个流行的 BDD 测试框架,两者都可以用来编写用户故事和可执行的测试用例,
具体选择哪一个则需要根据实际的项目状况来看。
先简单看一下两者的功能:
pytest-bdd
- 基于
pytest
测试框架,可以与pytest
的其他功能(例如 fixtures)一起使用。 - 提供了一种紧凑的步骤定义方式,可以通过装饰器定义并重复使用步骤。
- 支持参数化的测试,这样可以用同一组步骤进行多组数据的测试。
behave
- 基于 Python 的
unittest
测试框架。 behave
的步骤文件更加接近纯文本形式,对非编程人员更友好。- 支持使用
environment.py
文件来定义在整个 test suite 运行前后需要进行的操作。
hehave
以下是behave
的一些优点和特性:
-
适用于非技术团队成员:使用 Gherkin 语言,可以撰写更接近自然语言的测试场景描述,使得产品经理、商业分析师等非技术团队成员也能够理解、修改或编写测试场景。
-
环境控制:
behave
提供了在测试运行前后设置和清理环境的功能,例如数据库初始化或数据清理等,只需要在environment.py
文件里定义相应的函数即可。 -
可读性强和可维护性高:
behave
强调的是实现从用户角度去描述系统行为的测试,这使得测试和实际用户需求更加贴合,增加了测试的可读性。而且将测试用例编写为人类可读的语言,可以提高代码的可维护性。 -
创造可共享的步骤:可以为常用的操作创建可重用的步骤,这样就能写出更加简洁、易于维护的测试代码。
-
对标/兼容 Cucumber:
behave
的 Gherkin 语言实现与宽广使用的 Cucumber 测试框架非常接近,这一点在迁移到或从 Cucumber 环境中迁出时会很有用。 -
与其他 Python 测试框架相容:
behave
可与unittest
、doctest
、nose
、py.test
等 Python 测试工具完美集成。
综上所述,behave
提供了一种高度可读、可共享、适合大规模测试及非技术团队成员的 BDD 测试工具。
pytest-bdd 与 behave的比较
behave
和pytest-bdd
都是 Python 下常用的为支持 BDD(行为驱动开发)流程而设计的测试框架,它们都采用.feature
文件来描述行为,并使用相似的 Gherkin 语言语法进行描述。它们的.feature
文件的格式大致上是相同的,但是在实际的使用和处理上可能会有一些细微差别。
以下是behave
和pytest-bdd
来处理.feature
文件的一些细节差异:
-
Scenario 参数化:
behave
使用Scenario Outline
语法来实现参数化场景,而pytest-bdd
使用Scenarios
来实现参数化场景。在behave
中,你必须定义 Examples 表格并在其中提供参数值, 而在pytest-bdd
中,你可以简单地用Scenarios
读取一个外部.feature
文件。 -
装饰器参数:在
pytest-bdd
中,步骤装饰器(例如@given
、@when
和@then
)可以接受一个可选的解析器,用于从步骤文本中捕获值。这样,分析器可以为已经定义的步骤参数提供多个场景。
其他大部分方面,behave
和pytest-bdd
都是非常相似的,例如都支持Given
、When
和Then
这样的基本步骤,都允许在Background
段落中定义在每个场景前都要运行的步骤,仍然允许你创建可重用的步骤定义。
综上,behave
和pytest-bdd
处理.feature
文件的方式非常相似,虽然在某些特性和实现上有些许差别。选哪个更多取决于个人或团队需求。
pytest-bdd 与 behave的实例比较
接下来以一个具体的加法运算器为实例,初步演示两者使用上的差异。
首先, 两者的规格文件基本相同, 这里的文件名是 :calculator.feature,内容如下:
Feature: Addition
Scenario: Add two numbers
Given I have a calculator
When I enter "1" and "2"
Then the result should be "3"
规格很简单, 就是验证加法, 1+2 =3。
主要的差别是两者在测试代码上的差异。
使用pytest-bdd编写的测试代码的文件名是 test_calculator.py, 内容如下:
import sys
import os
import pytest
#sys.path.append('D:/devworkspace/python-ency/chp3/tests/bdd/util')
sys.path.append(os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'util'))
from calculator import Calculator
from pytest_bdd import scenario, given, when, then, parsers
@scenario('../features/calculator.feature','Add two numbers')
def test_add():
print(sys.path.append(os.path.dirname(os.path.dirname(__file__))+'util'))
pass
@pytest.fixture
@given("I have a calculator")
def calculator():
return Calculator()
@when(parsers.parse('I enter "{a}" and "{b}"'))
def enter_numbers(calculator, a, b):
calculator.a = int(a)
calculator.b = int(b)
@then(parsers.parse('the result should be "{result}"'))
def verify_result(calculator, result):
assert calculator.add(calculator.a, calculator.b) == int(result)
- pytest-bdd要求测试场景的函数和名称需要以test_开头, 步骤函数没有特定的要求,关于 pytest-bdd的更多命名的规范可以参考: 基于pytest-bdd的项目目录结构和命名规范
使用behave编写的测试代码的文件名同样是 test_calculator.py, 内容如下:
import sys
import os
sys.path.append(os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__)))), 'util'))
from behave import given, when, then
from calculator import Calculator
@given('I have a calculator')
def step_impl(context):
context.calc = Calculator()
@when('I enter "{num1}" and "{num2}"')
def step_impl(context, num1, num2):
context.result = context.calc.add(int(num1), int(num2))
@then('the result should be "{expected_result}"')
def step_impl(context, expected_result):
assert context.result == int(expected_result)
简单对比一下两者的测试代码区别:
- Beave 的写法相比更加简洁
- pytest-bdd 可以手动关联测试场景,看上去灵活度更高
总结
这两个框架都有其优点和特性,选择哪一个主要取决于特定需求。
- 如果你已经在使用
pytest
,并且希望以最少的学习曲线使用 BDD,那么pytest-bdd
可能是更好的选择。 - 另一方面,如果你希望编写的测试代码更接近自然语言,并且适合非技术团队成员阅读和修改,那么
behave
可能是更好的选择。