写点什么

那些 BDD 中用到的工具们

  • 2013-05-23
  • 本文字数:3031 字

    阅读完需:约 10 分钟

什么是 BDD?

BDD 在 wikipedia 上定义如下:

BDD 是第二代的、由外及内的、基于拉 (pull) 的、多方利益相关者的 (stakeholder)、多种可扩展的、高自动化的敏捷方法。它描述了一个交互循环,可以具有带有良好定义的输出(即工作中交付的结果):已测试过的软件。

简单一点地说,BDD,即行为驱动开发,是通过与产品经理沟通需求,定义出满足这些需求的软件需具备的行为 (Behaviour),再以这些行为为驱动 (Driven),编写产品代码来实现这些行为。(Development)。BDD 的出现,是为了解决测试驱动开发中常遇到的问题,比如:从哪里开始测试,应该测试什么,不应该测试什么,等等。想了解更多可参见 Dan North 的 introducing BDD。

BDD 实践所面临的问题

进行 BDD 实践首先要解决如下几个问题:

  • 如何实现一个能够描述系统行为(业务价值)、非技术人员可读的测试?
  • 如何让这个测试变得可执行?

业界对这些问题已经有了答案, JBehave , Cucumber Concordian 等 BDD 框架的出现,解决了这个问题。 这些 BDD 框架各自提供了一套 DSL(Domain-Specific-Language),开发人员可以使用 DSL 描述业务需求,例如,

复制代码
前置条件:
用户 A 账户余额 1000
用户 B 账户余额 200
场景:
用户 A 登录系统
向用户 B 转账 500
用户 A 账户余额应为 500
用户 B 庄户余额应为 700

同时,这些框架都依赖于 Webdriver(如 selenium-webdriver,watir-webdriver),BDD 框架通过 webdriver 调用浏览器的接口,模拟用户输入,读取浏览器页面上显示的内容用于验证。

下面我们通过一个完整的例子来看看如何使用这些工具进行 BDD 实践的。

Cucumber 与业务价值

在 Behaviour Driven Development 中,第一步就是把需求细分为多个任务,拿最常见的用户登录功能为例,可以划分为以下几个任务:

  • 用户名密码匹配,登录成功
  • 用户名或密码不匹配,登录失败

BDD 强调“每一个测试需要体现出业务价值”,因此,可以把上述两个任务实现为两个场景:

复制代码
Feature: User login
Background: There is a user with the following login detail:
| email | password|
| my@example.com| test |
Scenario: Login succeed
Given the user login with the following detail:
| email | password|
| my@example.com| test |
Then the user should login succeed
Scenario: Login failed
Given the user login with the following detail:
| email | password |
| my@example.com| wrongpassword |
Then the user should login failed

实际上,上面的这段代码就是使用 cucumber 的 DSL 描述的测试场景,几乎就是遵循了一定格式的英语,即使看不懂代码的产品经理、业务分析师也能够通过此文档和开发人员顺畅地交流。用 Cucumber 把一个需求的不同场景描述出来,也是从不同角度阐述了这个需求的业务价值。Cucumber 的目标就是书写可执行的,能够表述业务价值文档。 与之类似的框架还有 Concordian,JBehave 等。

紧接而来的问题是:如何让文档执行起来?Cucumber 提供了把业务逻辑转换为可执行代码的机制——“step definition”。请看下面的例子:

复制代码
Given /^the user login with the following detail:$/ do |detail|
#omitting code…
end

这个 step definition 会匹配下面这个 step:

复制代码
Given the user login with the following detail:
| email | password|
| my@example.com| test |

当 Cucumber feature 被执行的时候,这个 step definition 中的代码会被执行。那么,接下来的问题就是:如何象真实用户那样打开浏览器,输入用户名密码,点击提交按钮,验证登录是否成功。这时候,该 Webdriver 出场了。

Web Driver 与页面交互

先来看下面一段代码:

复制代码
require 'watir-webdriver'
b = Watir::Browser.new
b.goto 'http://localhost:3000/login'
b.text_field(:id => 'email').set 'my@example.com'
b.text_field(:id => 'password').set 'password'
b.button(:name => 'submit').click
b.text.include? 'Login succeed'

这段代码会做如下事情:

  1. 打开浏览器,访问 h 地址 “ http://localhost:3000/login”
  2. 在邮件输入框输入 “my@example.com”
  3. 在密码输入框输入 “password”
  4. 点击 提交按钮
  5. 验证结果页面是否包含“Login succeed”字样

这就是 webdriver 所提供的能力,web driver 通过调用浏览器的支持自动化的 API,模拟真实用户在浏览器上的操作。把这段代码被放在上面的 step definition 中,当 cucumber 测试运行的时候,这段代码就会运行,完成登录操作。这个例子是使用 Watir webdriver 实现的,另外一个比较流行的 webdriver 是 Selenium webdriver

不同 Webdriver 提供的 API 也不尽相同,而 Capybara 则致力于封装多种 web driver 之间的差异。同时,Capybara 提供了一些更聪明的特性,例如,等待页面加载完成再执行下一个步骤,这对于开发人员来说非常重要,否则,就需要自己判断写代码页面加载完成,代码丑陋,测试脆弱,那将是开发人员的噩梦。

Page Model 与页面建模

至此,一个可执行的描述用户登录的测试用例就编写完毕,当我们执行这个测试用例时,就会看到:

复制代码
浏览器打开
访问登录页面
在页面上输入用户名
密码
点击登录按钮
登录成功
测试通过

上述所有操作都是自动完成,一切都很完美,但前提是只在这样的一个小示例里。在一个实际的项目里,我们经常会遇到下面几个问题:

  1. 当越来越多的与页面交互的代码出现在 step definition 中时,页面交互,结果验证的代码混杂在一起,代码的可读性急剧下降。
  2. 因为 webdriver 与浏览器交互时依赖于页面元素的 id、name 等属性,对页面元素的任何小的修改都可能会导致测试失败。
  3. 在多个 step definition 与同一个页面交互时,可能会有冗余代码。

page model的出现就是为了解决上述问题,通过对页面的属性,交互动作进行抽象,封装以达到功能重用,隔离变化的目的。请看下面的例子:

Page model 定义
复制代码
class PageWithLogin
def url
#omitting code
end
def login email, password
#omitting code
end
end
class PageWithLoginResult
def login_succeed?
#omitting code
end
end
Step 定义
复制代码
Given /^the user login with the following detail:$/ do |detail|
on_page_with :login do |page|
visit page.url
page.login(detail["email"], detail["password"])
end
end
Given /^the user should login succeed$/ do |detail|
on_page_with :login_result do |page|
page.login_succeed?.should == true
end
end

如上,把loginlogin_succeed?功能封装到PageWithLogin, PageWithLoginResult这两个 page model 中,当"登录页面",“登录成功页面”的页面结构发生变化时,只需要修改 page model 中的实现即可,step 定义无需任何变化。关于 page model,我的同事徐昊曾经专门写过一篇文章

结论

BDD 框架通过提供 DSL,帮助业务人员,测试人员,开发人员定义需求的验收标准,共同得到一个明确的需求完成的定义。通过和 webdriver 集成,使这个验收标准变得可执行,大大减少了手工验证的压力,当软件通过了这个验收标准,则意味着这个需求已经开发完成。

注解与参考

  1. The truth about BDD Robert C Marting
  2. introducting BDD Dan North
  3. BDD on Wikipedia

感谢张凯峰对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ )或者腾讯微博( @InfoQ )关注我们,并与我们的编辑和其他读者朋友交流。

2013-05-23 06:035789

评论

发布
暂无评论
发现更多内容

百度与赛诺菲签订许可协议,开启新一代mRNA药物和疫苗研发

百度大脑

人工智能 百度

对象池模式(Object Pool Pattern)

Tom弹架构

Java 架构 设计模式

低代码实现探索(一)组件元信息定义

零道云-混合式低代码平台

低代码

阿里大牛最新公开压轴的“Redis深度笔记”,GitHub已标星81.6K

热爱java的分享家

Java 架构 面试 程序人生 编程语言

看完了阿里大牛的Leetcode刷题笔记, 我成功拿到了字节跳动的offer

热爱java的分享家

Java 面试 算法 LeetCode 经验分享

【高并发】浅谈AQS中的ReentrantLock、ReentrantReadWriteLock、StampedLock与Condition

冰河

Java 并发编程 多线程 高并发 异步编程

Flink Forward Asia 2021 延期,线上相见

Apache Flink

大数据 flink 编程 后端 实时计算

空对象模式(Null Object Pattern)

Tom弹架构

Java 架构 设计模式

修复一个BaseRecyclerViewAdapterHelper漏洞

Changing Lin

11月日更

回顾“低代码”历史发展,是技术进步了还是倒退了?

优秀

低代码

编写Java程序启动脚本最佳实践

WindFlying

面试不慌,拿这70张思维导图,怒怼面试官

奔着腾讯去

c++ golang 数据结构 思维导图 TCP/IP

雇工模式(Employee Pattern)

Tom弹架构

Java 架构 设计模式

字节大牛把算法常见面试:哈希、链表、队列、递归全部总结出来了

热爱java的分享家

Java 面试 程序人生 编程语言 经验分享

25 K8S之Endpoint对象

穿过生命散发芬芳

k8s 11月日更

Camtasia局部放大特效教程

淋雨

Camtasia 录屏

Spring Boot的前世今生以及它和Spring Cloud的关系详解

Java高级开发

Java 架构 springboot SpringCloud

简述以太坊P2P网络之UDP

devpoint

区块链 以太坊 udp 11月日更

不是吧,都2021年了你别说你还不会Spring MVC基本应用

热爱java的分享家

Java 架构 程序人生 编程语言 经验分享

API 编排的应用及痛点

全象云低代码

微服务 低代码 api 网关 API 编排

Flink CDC 2.1 正式发布,XTransfer技术专家贡献MongoDB CDC 连接器

XTransfer技术

大数据 实时计算

低代码实现探索(二)低代码中的数据

零道云-混合式低代码平台

低代码

终于有腾讯架构师把困扰我多年的《计算机网络原理》全部讲明白了

热爱java的分享家

Java 面试 编程语言 网络协议 经验分享

TypeScript 之 Indexed Access Types

冴羽

JavaScript typescript html5 大前端 ES6

规格模式(Specification Pattern)

Tom弹架构

Java 架构 设计模式

按需引入ant-design-vue组件

石云升

Vue 11月日更

数据分析从零开始实战,Pandas读写CSV数据

老表

Python 数据分析 pandas 11月日更

XTransfer 1号技术员工卡乐:从普通程序猿到技术专家

XTransfer技术

金融科技 支付 经验分享 创业公司

Python Qt GUI设计:QSlider滑动条类(基础篇—16)

不脱发的程序猿

Python PyQt GUI设计 Qt Designer QSlider滑动条类

萝卜快跑:迎来首单业绩兑现,商业化试点服务进程进入新阶段

脑极体

Go语言学习查缺补漏ing Day7

Regan Yue

Go 语言 11月日更

那些BDD中用到的工具们_研发效能_任晓君_InfoQ精选文章