BDD测试环境搭建

Cucumber

Posted by Young on March 7, 2019

什么是BDD

行为驱动开发(英语:Behavior-driven development,缩写BDD)是一种敏捷软件开发的技术,它鼓励软件项目中的开发者、QA和非技术人员或商业参与者之间的协作。BDD最初是由Dan North在2003年命名,它包括验收测试和客户测试驱动等的极限编程的实践,作为对测试驱动开发的回应。

BDD的重点是通过与利益相关者的讨论取得对预期的软件行为的清醒认识。它通过用自然语言书写非程序员可读的测试用例扩展了测试驱动开发方法。行为驱动开发人员使用混合了领域中统一的语言的母语语言来描述他们的代码的目的。这让开发者得以把精力集中在代码应该怎么写,而不是技术细节上,而且也最大程度的减少了将代码编写者的技术语言与商业客户、用户、利益相关者、项目管理者等的领域语言之间来回翻译的代价。

Dan North创造了首个BDD框架:JBehave;之后是Ruby语言的基于故事的RBehave,后来被纳入了RSpec项目。他还与大卫赫利姆斯基、Aslak Hellesøy及其他人开发了RSpec,并一起编写了《The RSpec Book: Behaviour Driven Development with RSpec, Cucumber, and Friends》。RSpec中第一个基于故事的框架,后来被主要由Aslak Hellesøy开发的Cucumber取代。

2008年,参与了围绕BDD进行的首轮讨论的克里斯马茨,提出了特性注入(Feature Injection)的想法,使BDD可以覆盖分析空间并提供从初期的展望到编码和发布的整个软件生命周期过程的改造。

BDD实践

BDD的做法包括:

  • 确立不同利益相关者要实现的远景目标

  • 使用特性注入方法绘制出达到这些目标所需要的特性

  • 通过由外及内的软件开发方法,把涉及到的利益相关者融入到实现的过程中

  • 使用例子来描述应用程序的行为或代码的每个单元

  • 通过自动运行这些例子,提供快速反馈,进行回归测试

  • 使用“应当(should)”来描述软件的行为,以帮助阐明代码的职责,以及回答对该软件的功能性的质疑

  • 使用“确保(ensure)”来描述软件的职责,以把代码本身的效用与其他单元(element)代码带来的边际效用中区分出来。

  • 使用mock作为还未编写的相关代码模块的替身

Cucumber环境搭建

ruby及cucumber安装

window下安装ruby, 推荐使用rubyinstaller

ruby下载页面: https://rubyinstaller.org/downloads/

安装cucumber, 推荐使用ruby的gem包管理工具进行安装(PS:gem的软件源网络比较抽风, 能不能安装好主要看运气)

  • 打开windows的cmd, 输入gem install cucumber

编辑器及插件安装

VSCode下载页面: https://code.visualstudio.com/

VsCode扩展位置如下图所示,安装图中标红的三个插件 VsCode扩展位置

安装ruby插件

在vscode中安装ruby插件后,打开cmd, 输入gem install ruby-debug-ide, 安装ruby-debug-ide

debug演示

  • 新建项目的文件夹, 如demo, demo下包含test.rb文件
  • 在VSCode中点击文件->打开文件夹->选择demo
  • 在demo下新建.vscode目录
  • demo/.vscode下新建launch.json文件
  • launch.json文件中输入以下内容:
{
    // 使用 IntelliSense 了解相关属性。 
    // 悬停以查看现有属性的描述。
    // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Debug Local File",
            "type": "Ruby",
            "request": "launch",
            "cwd": "${workspaceRoot}",
            "program": "${workspaceRoot}/test.rb",  // 调试单个文件时, 需要填写对应的文件名和相对路径
        }
    ]
}

点击调试, 选择刚刚配置中的名称”Debug Local File”, 打上断点后按F9进行调试, 如下图: 调试demo

安装cucumber插件

在vscode中安装cucumber插件后,在demo/.vscode下新建settings.json文件。 在setting.json文件中输入:

{
    "cucumberautocomplete.steps": [
        "features/step_definitions/*.rb",
    ],
    "cucumberautocomplete.syncfeatures": "features/*feature",
    "cucumberautocomplete.strictGherkinCompletion": true
}

运行你cucumber下的第一个Feature

在终端中输入cucumber --init。 在新生成的feature目录下, 新建demo.feature。 在demo.feature文件中输入以下内容:

# language : zh-CN
功能: 今天是星期五吗?

   大家都想知道哪一天是星期五

   场景: 星期天不是星期五
    假如 今天是星期天
    当 我问今天是不是星期五
    那么 我被告知"今天不是星期五"

在终端中输入cucumber, 则得到以下运行结果

*** WARNING: You must use ANSICON 1.31 or higher (https://github.com/adoxa/ansicon/) to get coloured output on Windows
# language : zh-CN
功能: 今天是星期五吗?

   大家都想知道哪一天是星期五

   场景: 星期天不是星期五
    假如 今天是星期天
    当 我问今天是不是星期五
    那么 我被告知"今天不是星期五"

1 scenario (1 undefined)
3 steps (3 undefined)
0m0.067s

You can implement step definitions for undefined steps with these snippets:

假如("今天是星期天") do
  pending # Write code here that turns the phrase above into concrete actions
end

当("我问今天是不是星期五") do
  pending # Write code here that turns the phrase above into concrete actions
end

那么("我被告知{string}") do |string|
  pending # Write code here that turns the phrase above into concrete actions
end

此时根据提示用自动化实现对应的步骤。 在step_definitions目录下新建demo.rb, 并填入以下代码:

假如("今天是星期天") do
  pending # Write code here that turns the phrase above into concrete actions
end

当("我问今天是不是星期五") do
  pending # Write code here that turns the phrase above into concrete actions
end

那么("我被告知{string}") do |string|
  pending # Write code here that turns the phrase above into concrete actions
end

再次在cmd中运行cucumber, 此时显示场景待办(pending)

*** WARNING: You must use ANSICON 1.31 or higher (https://github.com/adoxa/ansicon/) to get coloured output on Windows
# language: zh-CN
功能: 今天是星期五吗?
   大家都想知道哪一天是星期五

  场景: 星期天不是星期五      # features/demo.feature:6
    假如今天是星期天        # features/step_definitions/demo.rb:14
      TODO (Cucumber::Pending)
      ./features/step_definitions/demo.rb:15:in `"今天是星期天"'
      features/demo.feature:7:in `假如今天是星期天'
    当我问今天是不是星期五     # features/step_definitions/demo.rb:19
    那么我被告知"今天不是星期五" # features/step_definitions/demo.rb:24

1 scenario (1 pending)
3 steps (2 skipped, 1 pending)
0m0.079s

接下来我们来实现一下demo.rb中对应的步骤,代码如下所示:

module StepHelper
  def is_it_friday(today)
    if today == '星期五'
      '今天是星期五'
    else
      '今天不是星期五'
    end
  end
end

World StepHelper # 将StepHelper模块添加到当前运行的实例中来


假如("今天是星期天") do 
     @today = '星期天' 
end

当("我问今天是不是星期五") do 
     @actual_answer = is_it_friday(@today) 
end

那么("我被告知{string}") do |expected_answer| 
     expect(@actual_answer).to eq(expected_answer)  # 断言cucumber官方推荐使用rspec-expectations, 需要在cmd中安装, gem install rspec-expectations
end

此时运行结果为:

*** WARNING: You must use ANSICON 1.31 or higher (https://github.com/adoxa/ansicon/) to get coloured output on Windows
# language: zh-CN
功能: 今天是星期五吗?
   大家都想知道哪一天是星期五

  场景: 星期天不是星期五      # features/demo.feature:6
    假如今天是星期天        # features/step_definitions/demo.rb:14
    当我问今天是不是星期五     # features/step_definitions/demo.rb:18
    那么我被告知"今天不是星期五" # features/step_definitions/demo.rb:22

1 scenario (1 passed)
3 steps (3 passed)
0m0.078s

到此, 我们的第一个cucumber功能用例就通过了,接下来我们看一下如何调试cucumber的代码。

debug演示

.vscode/launch.json文件的”configurations”中加入以下代码:

{
            "name": "Cucumber",
            "type": "Ruby",
            "request": "launch",
            "cwd": "${workspaceRoot}",
            "program": "C:/Ruby25-x64/bin/cucumber",  //此处为本机安装cucumber的路径
},

.vscode/launch.json文件完整代码如下:

{
    // 使用 IntelliSense 了解相关属性。 
    // 悬停以查看现有属性的描述。
    // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Cucumber",
            "type": "Ruby",
            "request": "launch",
            "cwd": "${workspaceRoot}",
            "program": "C:/Ruby25-x64/bin/cucumber",
        },
        {
            "name": "Debug Local File",
            "type": "Ruby",
            "request": "launch",
            "cwd": "${workspaceRoot}",
            "program": "${workspaceRoot}/test.rb",  // 调试单个文件时, 需要填写对应的文件名和相对路径
        }
    ]
}

此时点击调试, 在选择刚刚配置中的名称”Cucumber”, 打上断点后按F9进行调试, 如下图: 调试cucumber

参考文档

名称 简要 链接
行为驱动开发 wiki https://zh.wikipedia.org/wiki/行为驱动开发
cucumber 官方文档 https://docs.cucumber.io/
rspec-expectations 断言库 https://github.com/rspec/rspec-expectations