前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >醒醒吧少年,只用Cucumber不能帮助你BDD | TW洞见

醒醒吧少年,只用Cucumber不能帮助你BDD | TW洞见

作者头像
ThoughtWorks
发布2018-04-20 13:56:01
8990
发布2018-04-20 13:56:01
举报
文章被收录于专栏:ThoughtWorksThoughtWorks

今日洞见

文章作者来自ThoughtWorks:毛超。

本文所有内容,包括文字、图片和音视频资料,版权均属ThoughtWorks公司所有,任何媒体、网站或个人未经本网协议授权不得转载、链接、转贴或以其他方式复制发布/发表。已经本网协议授权的媒体、网站,在使用时必须注明"内容来源:ThoughtWorks洞见",并指定原文链接,违者本网将依法追究责任。

1

引言

在Ruby社区中,测试和BDD一直是一个被热议的话题,不管是单元测试,集成测试和功能测试,你总能找到能帮助你的工具,Cucumber就是被广泛使用的工具之一。许多团队选择Cucumber的原因是“团队要BDD”,也就是行为驱动开发(Behavior Driven Development),难道用了Cucumber之后团队就真的BDD了么?

事情当然没这么简单了,BDD作为一种软件开发方法论,一定要理解其含义并且遵循特定的流程,工具只不过是起辅助作用而已。会切菜的不一定都是厨子,会写代码的不一定都是程序员。近期Cucumber的作者Aslak也在博客中提到

在BDD出现的9年后,依然有不少团队在使用BDD时出现问题……BDD依然经常被人误解成单纯的测试,或者是一个可以被下载的工具

同时,Aslak也吐槽了Cucumber目前的处境

就在最近,Cucumber已经被下载了超过500万次,我很高兴它如此受欢迎,同时也为它被广泛的误用而感到失望……Cucumber有时依然被错误的当成了自动化测试工具,而不是我当时创建的东西。

那么问题来了,怎样在日常项目中使用Cucumber呢?真的能在日常项目中进行BDD开发么?要回答这个问题,我们需要重新认识一下BDD。

2

BDD的提出

2003年,开发人员Dan North偶然间发现把测试的标题经过简单的文字处理可以更好表达代码蕴含的业务逻辑,比如下面这段代码,

public class CustomerLookupTest extends TestCase {

testFindsCustomerById() {

...

}

testFailsForDuplicateCustomers() {

...

}

}

当我们把测试方法中的test去掉,给单词加上空格,然后把他们组合在一起时,就会出现:

CustomerLookup

- finds customer by id

- fails for duplicate customers

- ...

在Dan看来,这无疑是对CustomerLookup类的描述,并且是用测试内容来描述代码中类的行为。Dan发现他似乎找到了一种方式,可以在TDD的基础上,通过测试来表达代码的行为。在尝到甜头后,Dan写了JBehave,一个更关注代码行为的工具来代替JUnit进行软件开发。经过一番折腾后,Dan觉得只描述类行为不过瘾,便开始把关注点从类扩展到整个软件,他和当时项目组的业务人员一起把需求转化成Given/When/Then的三段式,然后用JBehave写成测试来描述软件的某种行为。当测试完成后,开发人员才开始编码,一旦测试通过,那软件就完成了测试中描述的某种行为。在他看来,他把TDD升级了,因为他不再只关注于局部类的方法,而开始关注整个软件的行为。

通过这种方式,Dan成功的把需求转换成了软件的功能测试,先写功能测试再驱动出产品代码,保证软件行为正确性。其次,Dan强调在测试中要尽可能的使用业务词汇,保证团队成员对业务理解一致。于是,BDD就此诞生。

3

BDD不只是自动化测试

在上面的故事中,“测试”这个词出现了很多次,你是不是已经认为BDD就是用功能测试驱动产品代码的开发流程呢?其实不然,功能测试只是一个结果而已,更重要的是和业务人员一起分析需求,沟通交流来产生测试的过程。用测试驱动出来的代码可以保证是正确的,但如何保证测试是正确的呢?答案就是人,通过业务,开发和测试一起参与生成的测试文档,不仅能保证软件功能上是正确的,还能保证团队成员对业务理解是一致的。在测试文档中,也应该尽量保证使用自然语言和业务词汇,减少非技术人员的学习成本。

在多年之后,Dan也终于给出了他对BDD的定义

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

Cucumber的另一位作者Matt Wynne也给出了自己的定义

BDD的实践者们通过沟通交流,具体的示例和自动化测试帮助他们更好地探索,发现,定义并驱动出人们真正想用的软件

从上述定义我们可以看出,BDD更强调流程和一系列实践,自动化测试只是其中一部分而已。

4

Cucumber到底怎么用

理解了BDD的精髓后,我们就不难找出正确的使用Cucumber的方式了。根据Cucumber的定义,它的核心就是Specification,其实就是文档化的需求。Specification是通过Requrement Workshop生成的,在Workshop中业务,开发和测试一起分析需求,把需求用自然语言写成文档,然后再转换成Given/When/Then的Specification文件,这样便完成了BDD中最重要的一步,定义软件正确的行为。接着开发人员开始编码,完成相应需求,保证Specification文件运行通过,整个流程结束。

简单来说,Cucumber其实不是一个自动化测试工具,而是一个促进团队沟通合作的工具。但由于Cucumber无法确保上述流程真正的发生,有很多团队简化或者跳过了Workshop,直接开始写Specification文件,没有沟通就很难保证理解一致,Bug也许就在那时潜伏了下来。这样大家也就不难理解作者吐槽的“Cucumber被广泛的误用”,其实Cucumber只是一个沟通工具,它只是刚巧可以运行测试而已。

5

理想很丰满,现实很骨感

任何工具和实践都有优缺点,Cucumber也不例外。团队在开始尝试新的实践或者工具时,多多少少都会碰到一些问题,下面我们就来看看一些使用Cucumber的问题。

没有业务人员参与的Specification

要么业务人员没时间写Specification,交给其他人写,写完之后业务人员也没时间去审核。在这种情况下,很难保证Specification的业务正确性,一旦Specification出现问题,团队可能发生理解不一致,甚至做错需求的现象。反过来看,Specification文件由自然语言而不是代码组成,也能反映出对非技术人员参与的重视程度。然而现实情况很难保证业务、测试、开发有充足的时间进行Specification的讨论和编写,这也是导致业务人员逐渐脱离Specification的主要原因。

Specification关注实现细节而不是业务逻辑

Cucumber使用自然语言描述业务需求,然而不少团队都陷入到了实现细节中。比如

Scenario: Detect agent type based on contract number

Given I am on the 'Find me' page

And I have entered a contract number

When I click 'Continue' button

And a contact number match is found

Then the "Back" button will be displayed

上面的描述满篇是点击了那个按钮,输入了什么内容,看完之后反而让人有点困惑,用户到底为什么要做这些,做了之后有什么价值。这样的Specification既不能满足团队成员对业务需求的了解,也会由于界面的细微改动运行失败。

Step的嵌套调用

Specification文件由Step组成,在Step中我们可以通过Ruby进行自动化的页面操作。有时我们会发现某些Specification会重复进行一系列的操作,这时我们就可以把重复的Step进行组合,创建出新的Step。比如这样

Given there is student Harry

And there is professor Snape

And student Harry joins class of professor Snape

# use 1 new step instead of 3

Given student Harry in class of professor Snape

那么这个新的Step该怎么实现呢?Cucumber支持在Step中调用Step,比如这样

Given /^student (.*) in class of professor (.*)/ do |student, professor|

step "there is student #{student}"

step "there is professor #{professor}"

step "student #{student} joins class of professor #{professor}"

end

乍一看好像没什么问题,其实不然。Step使用正则表达式进行匹配,问题恰恰出在正则上。

首先,正则灵活性很大,你确定上面例子中step “there is student #{student}”一定会调用到你想要调用的Step么?你无法确定在运行时,是否会出现另一个Step “there is student come from China”来截胡。

其次,正则逆推难度很大,也就是说当你看到“^(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]).(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0).(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0).(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])$”时,你很难看出这是在匹配IP地址。所以当我们需要修改step时,很难确定有多少个step在依赖它,这也加大了维护成本。

最后,嵌套次数过多的Step也会导致代码复杂,难以理解。

Specification Report可读性不高

Specification除了是自动化测试的描述文件之外,更重要的是软件的“活文档”。有时我们需要通过“活文档”进行知识传递。Cucumber虽然提供生成Report功能,但效果未免有些差强人意。比如下面

满篇绿色的Step,再加上Given/When/Then来捣乱,这样的Report只是运行结果而已,可读性很差,很难当成软件需求文档。究其原因,主要因为Cucumber Report的表现力差。

首先,它只支持纯文本,在这个“一图胜千言,无图无真相”的时代很难只通过文字来描述复杂业务,如果能在文档中加上图片,甚至一段视频,都会帮助我们更容易的理解复杂业务。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2015-11-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 思特沃克 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档