写点什么

那些 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:036124

评论

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

Spring高手之路8——Spring Bean模块装配的艺术:@Import详解

砖业洋__

@Import 模块装配 Import注解 ImportSelector Spring动态装配

关于互联网产业的一些思考

用友BIP

产业互联网

中移链与BSN分布式云管平台集成,共同构建专属协同体系

BSN研习社

LigaAI:从效率、度量和价值维度,成为研发团队的智能医生

LigaAI

研发管理 SaaS 研发协作平台 TO B 企业号 7 月 PK 榜

Spring高手之路9——掌握Spring条件装配的秘密武器

砖业洋__

spring Spring配置 @Profile @Conditional 条件装配

企业数智化底座赋能国资国企数智监管

用友BIP

数智底座 国资国企

倒计时 1 天!21 位大咖 11个议题,龙蜥社区走进 Intel MeetUp 即将在上海召开

OpenAnolis小助手

操作系统 芯片 intel Meetup 龙蜥社区

装备制造行业数智人力应从何入手?超实用干货来了!

用友BIP

人力资源

Spring高手之路7——事件机制与监听器的全面探索

砖业洋__

spring 观察者模式 事件机制 Spring生命周期 Spring 监听

pump 日志错误信息疑问之你的pump 数据被gc了嘛?

TiDB 社区干货传送门

性能调优 实践案例 集群管理 TiDB 源码解读

O-Star | 矩阵起源2023届校招生入职啦~

MatrixOrigin

数据库 云原生 HTAP MatrixOrigin MatrixOne

Spring高手之路4——深度解析Spring内置作用域及其在实践中的应用

砖业洋__

spring Singleton prototype Spring作用域 Spring原型作用域

绘出「星辰大海」:华为云Astro轻应用新手指南-第一章

华为云PaaS服务小智

云计算 华为 开发者 华为云

抽象语法树AST必知必会 | 京东物流技术团队

京东科技开发者

前端 AST 抽象语法树 企业号 7 月 PK 榜

全球LED显示屏市场机遇与挑战

Dylan

封装 芯片 LED显示屏 体育 全球

绘出「星辰大海」:华为云Astro轻应用新手指南-第二章

华为云PaaS服务小智

云计算 开发者 软件开发 华为云

日增320TB数据,从ClickHouse迁移至ByConity后,查询性能十分稳定!

字节跳动开源

大数据 开源 云原生 Clickhouse 数仓

# **基于TiDB Binlog架构的主备集群切换操作手册**

TiDB 社区干货传送门

实践案例 管理与运维

用 Generative AI 构建企业专属的用户助手机器人

TiDB 社区干货传送门

零基础能学习Java吗,看了这篇文章你就知道!

java易二三

记一次sst文件损坏修复过程

TiDB 社区干货传送门

故障排查/诊断

矩阵起源通过ISO 三大体系认证!

MatrixOrigin

数据库 超融合 HTAP MatrixOrigin MatrixOne

免费又好用的MES系统——万界星空MES系统重磅来袭

万界星空科技

开源

一文了解电商大促系统的高可用保障思路 | 京东云技术团队

京东科技开发者

产品 高可用 研发 电商大促 企业号 7 月 PK 榜

Spring高手之路6——Bean生命周期的扩展点:BeanPostProcessor

砖业洋__

spring ioc BeanPostProcessor Bean生命周期扩展点 后置处理器

7.25齐聚西安!助推国资国企建设一流司库管理体系

用友BIP

全球司库 国资国企

Ui2Code+ChatGPT助力低代码搭建 | 京东云技术团队

京东科技开发者

低代码 ChatGPT 企业号 7 月 PK 榜 Ui2Code

Spring高手之路5——彻底掌握Bean的生命周期

砖业洋__

Spring Bean Spring Bean生命周期 @PostConstruct InitializingBean DisposableBean

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