Python高级技术之:`Python`的`BDD`(行为驱动开发):`behave`和`lettuce`的实践。

各位观众老爷,大家好!我是你们的老朋友,今天咱们不聊虚的,直接上干货,讲讲Python里搞BDD(Behavior-Driven Development,行为驱动开发)的那些事儿。

开场白:为什么要搞BDD?

话说码农的世界,变化总是比女朋友的心情还快。需求变来变去,代码改来改去,一不小心就写成了"屎山"。 怎么办?BDD 就像一盏明灯,照亮我们前进的方向。

BDD的核心思想是:用自然语言描述软件的行为,然后把这些描述变成自动化测试。 这样一来,开发人员、测试人员、产品经理甚至客户都能看懂,避免了沟通上的误解,也让测试更加贴近用户的真实需求。

主角登场:Behave 和 Lettuce

Python里搞BDD,最常用的两个工具就是 Behave 和 Lettuce。它们都遵循 Gherkin 语法,让你用自然语言来描述你的测试场景。

  • Behave: 功能强大,社区活跃,文档完善,是目前Python BDD领域的事实标准。
  • Lettuce: 比较轻量级,语法更简洁,适合小型项目或者快速原型开发。

咱们今天主要以 Behave 为例,讲讲怎么玩转 BDD。

Gherkin 语法:像写故事一样写测试

Gherkin 是一种简单的、人类可读的语言,用于描述软件的行为。它主要由以下几个关键字组成:

  • Feature: 描述一个大的功能模块。
  • Scenario: 描述一个具体的场景,也就是一个测试用例。
  • Given: 描述场景的前提条件。
  • When: 描述用户的行为。
  • Then: 描述预期的结果。
  • And: 连接多个 Given、When、Then。
  • But: 和 And 类似,但表示一种例外情况。
  • Scenario Outline: 描述多个类似的场景,可以用表格来参数化。
  • Examples: 提供 Scenario Outline 中使用的参数。

举个例子,假设我们要测试一个简单的加法器:

# features/add.feature
Feature: 加法器

  Scenario: 两个正数相加
    Given 我输入数字 5
    And 我输入数字 3
    When 我点击“相加”按钮
    Then 结果应该为 8

  Scenario Outline: 多个数字相加
    Given 我输入数字 <num1>
    And 我输入数字 <num2>
    When 我点击“相加”按钮
    Then 结果应该为 <result>

    Examples:
      | num1 | num2 | result |
      | 1    | 2    | 3      |
      | 4    | 5    | 9      |
      | 7    | 8    | 15     |

这个 add.feature 文件描述了加法器的两个场景:一个是两个正数相加,另一个是多个数字相加。Scenario Outline 允许我们用不同的参数来运行同一个场景,避免了重复编写代码。

Behave 的使用:把故事变成代码

有了 feature 文件,接下来就要用 Behave 来运行它。首先,你需要安装 Behave:

pip install behave

然后,在你的项目目录下创建一个 features 目录,把 add.feature 文件放进去。接下来,创建一个 features/steps 目录,用来存放测试步骤的实现代码。

# features/steps/add.py
from behave import *

@given('我输入数字 {num}')
def step_impl(context, num):
    context.num = int(num)

@when('我点击“相加”按钮')
def step_impl(context):
    context.result = context.num + context.num

@then('结果应该为 {result}')
def step_impl(context, result):
    assert context.result == int(result)

这个 add.py 文件定义了三个测试步骤:

  • @given('我输入数字 {num}'):这个步骤对应 Given 关键字,它把输入的数字保存到 context 对象中。
  • @when('我点击“相加”按钮'):这个步骤对应 When 关键字,它执行加法操作,把结果保存到 context 对象中。
  • @then('结果应该为 {result}'):这个步骤对应 Then 关键字,它验证结果是否符合预期。

现在,你就可以运行 Behave 了:

behave

Behave 会自动找到 features 目录下的所有 feature 文件,然后按照 Gherkin 语法执行测试步骤。如果一切顺利,你会看到类似这样的输出:

1 feature passed, 0 failed, 0 skipped
3 scenarios passed, 0 failed, 0 skipped
9 steps passed, 0 failed, 0 skipped, 0 undefined
Took 0m0.000s

这意味着所有的测试都通过了!

高级技巧:Context 对象

在 Behave 中,context 对象是一个非常重要的东西。它可以用来在不同的测试步骤之间传递数据。例如,在上面的例子中,我们用 context.numcontext.result 来保存输入的数字和计算结果。

你还可以在 context 对象中添加自定义的属性和方法。例如,你可以创建一个 context.browser 对象来模拟浏览器行为,或者创建一个 context.database 对象来访问数据库。

表格:参数化测试的利器

Scenario OutlineExamples 允许我们用表格来参数化测试。这在测试多个类似的场景时非常有用。

例如,假设我们要测试一个计算器,它可以进行加法、减法、乘法和除法运算:

Feature: 计算器

  Scenario Outline: 计算器可以进行各种运算
    Given 我输入数字 <num1>
    And 我输入数字 <num2>
    When 我点击“<operator>”按钮
    Then 结果应该为 <result>

    Examples:
      | num1 | num2 | operator | result |
      | 1    | 2    | +        | 3      |
      | 4    | 5    | -        | -1     |
      | 7    | 8    | *        | 56     |
      | 9    | 3    | /        | 3      |

对应的测试步骤实现代码如下:

from behave import *

@given('我输入数字 {num}')
def step_impl(context, num):
    context.num = int(num)

@when('我点击“{operator}”按钮')
def step_impl(context, operator):
    if operator == '+':
        context.result = context.num + context.num
    elif operator == '-':
        context.result = context.num - context.num
    elif operator == '*':
        context.result = context.num * context.num
    elif operator == '/':
        context.result = context.num / context.num
    else:
        raise ValueError('Invalid operator: {}'.format(operator))

@then('结果应该为 {result}')
def step_impl(context, result):
    assert context.result == int(result)

通过使用表格,我们可以用更少的代码来测试更多的场景,提高了测试效率。

钩子函数:在测试前后做一些事情

Behave 提供了钩子函数,允许你在测试前后执行一些代码。例如,你可以在测试开始前启动一个 Web 服务器,或者在测试结束后关闭它。

Behave 提供了以下几种钩子函数:

  • before_all(context):在所有测试开始前执行。
  • after_all(context):在所有测试结束后执行。
  • before_feature(context, feature):在每个 feature 开始前执行。
  • after_feature(context, feature):在每个 feature 结束后执行。
  • before_scenario(context, scenario):在每个 scenario 开始前执行。
  • after_scenario(context, scenario):在每个 scenario 结束后执行。
  • before_step(context, step):在每个 step 开始前执行。
  • after_step(context, step):在每个 step 结束后执行。

你可以在 features/environment.py 文件中定义这些钩子函数。例如:

# features/environment.py

def before_all(context):
    print('测试开始!')

def after_all(context):
    print('测试结束!')

def before_scenario(context, scenario):
    print('Scenario: {} 开始!'.format(scenario.name))

def after_scenario(context, scenario):
    print('Scenario: {} 结束!'.format(scenario.name))

这些钩子函数可以让你在测试过程中做一些初始化和清理工作,例如:

  • 连接数据库
  • 启动 Web 服务器
  • 创建测试数据
  • 清理临时文件

Behave 配置:让测试更灵活

Behave 允许你通过配置文件来定制测试行为。你可以创建一个 behave.ini 文件,放在你的项目目录下,用来配置 Behave 的各种选项。

例如,你可以用 behave.ini 文件来指定 feature 文件的路径、测试步骤的路径、报告的格式等等。

# behave.ini
[behave]
paths = features
steps_path = features/steps
format = pretty

这个配置文件指定了:

  • paths = features:feature 文件放在 features 目录下。
  • steps_path = features/steps:测试步骤的实现代码放在 features/steps 目录下。
  • format = pretty:使用 pretty 格式来输出测试报告。

Behave 提供了很多配置选项,你可以根据自己的需要来定制测试行为。

Lettuce:轻量级的选择

虽然我们主要讲的是 Behave,但 Lettuce 也是一个不错的选择,特别是对于小型项目或者快速原型开发。

Lettuce 的语法和 Behave 类似,但更简洁一些。例如,Lettuce 没有 Feature 关键字,而是直接用 Scenario 来描述一个测试用例。

# features/add.feature (Lettuce)
Scenario: 两个正数相加
  Given 我输入数字 5
  And 我输入数字 3
  When 我点击“相加”按钮
  Then 结果应该为 8

Lettuce 的测试步骤实现代码也更简洁一些:

# features/steps.py (Lettuce)
from lettuce import *

@step('我输入数字 (.*)')
def step_impl(step, num):
    world.num = int(num)

@step('我点击“相加”按钮')
def step_impl(step):
    world.result = world.num + world.num

@step('结果应该为 (.*)')
def step_impl(step, result):
    assert world.result == int(result)

在 Lettuce 中,我们用 world 对象来代替 Behave 的 context 对象,用来在不同的测试步骤之间传递数据。

总的来说,Lettuce 比 Behave 更轻量级,更易于上手,但功能也相对简单一些。你可以根据自己的需要来选择合适的工具。

BDD 的最佳实践:让你的测试更有效

  • 用自然语言描述测试场景:让开发人员、测试人员、产品经理甚至客户都能看懂。
  • 从用户的角度思考:测试应该模拟用户的真实行为,而不是仅仅验证代码的内部逻辑。
  • 保持测试的简洁性:每个测试用例应该只测试一个功能点,避免测试过于复杂。
  • 编写可维护的测试代码:测试代码也需要精心设计,避免重复代码,提高可读性和可维护性。
  • 持续集成:把 BDD 测试集成到持续集成流程中,及时发现和修复 Bug。

总结:BDD,让开发更美好

BDD 是一种非常有用的软件开发方法,它可以帮助我们更好地理解用户需求,提高代码质量,减少沟通成本。Behave 和 Lettuce 是 Python 中两个常用的 BDD 工具,它们都遵循 Gherkin 语法,让你用自然语言来描述你的测试场景。

希望今天的讲座能帮助你更好地理解和应用 BDD。记住,编程的道路漫长而艰辛,但只要我们坚持学习,不断进步,就能创造出更美好的软件世界!

一个表格总结 Behave 和 Lettuce 的区别:

特性 Behave Lettuce
社区活跃度 非常活跃,文档完善 相对较小,文档较少
功能 功能强大,配置灵活 相对简单,配置较少
语法 遵循 Gherkin 语法 遵循 Gherkin 语法,更简洁
Context对象 使用 context 对象传递数据 使用 world 对象传递数据
适用场景 大型项目,需要灵活配置 小型项目,快速原型开发

希望这个表格可以帮助你更好地选择合适的 BDD 工具! 咱们下期再见!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注