如何编写好的cucumber场景

cucumber你需要了解的一些概念

如何描述场景

如何写出让利益相关人员阅读,同时又能被测试的规格说明。
Fred Books在《没有银弹》(No Silver Bullet)中提到:

构建软件系统,最困难的部分就是准确地决定到底构建什么。

所以开发和利益相关人更好的沟通是避免此类事件浪费的关键。需要一种有助于促进沟通的技术,所谓cucumber,就是来阐明我们想让开发做什么,想让软件成为什么。
在于相关人员沟通的过程中,他们能提供于我们有用的反馈和想法,他们能提供于我们所谓的验收标准和条件,我们创造系统告诉相关人什么才是真正能被验收的。如下需求描述:

应用只能允许用户输入合法的信息

这样的需求的描述本身没有问题,问题在于它提供的信息给产生歧义和误解留下了太多的空间,没有精确度。什么样的输入信息是合法的?

用户输入的手机号必须是11位,并且以1开头的数字,提交时应当显示"请输入正确的手机号",以提示用户正确的输入方式。

而这样的需求描述很明显是更加具体的,开发人员可以瞬间get到所有的条件和逻辑,相关人员也能更清楚得表达自己的需求。
如果能将这样的需求描述表达得如此清晰,以得到所有的逻辑条件,那么假如这些实例说明又能让计算机精准地阅读,并帮助我们完成应用的验证,又会如何呢?
我们在cucumber中用到了Gherkin,它提供了一种轻量的结构能让开发人员和业务相关人同时理解的自然语言,同时也是一种编程语言。

Scenario: Give me a cup of coffee
  Given I pay for the coffee
  And they made a cup of coffee
  Then they gave the coffee to me

有人认为Given, When, Then, And and so on,用起来比较繁琐,其实我们还可以使用*来代替,比如上述的场景可以描述为:

Scenario: Give me a cup of coffee
  * I pay for the coffee
  * they made a cup of coffee
  * they gave the coffee to me

这样的功能描述是非常精益的文档,他的描述也没有限制,如果你觉得很难描述应用的某个特性,那么如下的模板是个非常 nice 的开头

  1. 系统处于某种特定的状态
  2. 触动一下系统
  3. 检查系统的新状态

这样的一个场景,通常都是一个小小的故事,能描述系统的某个特性,或者这个应用能够做到的事情。你可以尝试使用Given, When, Then描述你手头在做的日常事务,比如做饭,开车,撕逼,打架、、Gherkin能描述一切场景,并且你也能熟悉如何使用它描述你的系统。

我们描述一个特性通常会用到5-20个场景来阐述,但是有一个非常重要的概念你需要掌握:

每个场景都必须有独立的意义,且能够不依赖任何其他场景独立运行。

每个场景构成联系并不会使cucumber报错,并且cucumber也没有理由阻止你这么做,但这确实是一种很差劲的实践,如果这么做,最终得到的场景描述可能会难以理解甚至出现难以预料的失败。
这是一个不成文的建议,初期可能会对我们描述场景产生阻碍,我们时常太依赖自然语言的思维,但是应该学会描述这类系统测试场景,在不同的场景之间构造一些脆弱的依赖不是一个很好的尝试。

如何编写步骤定义

cucumber扫描每个步骤的文本,是可以通过正则表达式匹配的,假如我们能抓住系统特性描述的规律,可以帮助我们可以用很少的模式处理大量的场景。
比如说:

  • 点击xxx
  • 存在xxx
  • xxx的文案是xxx
  • 存在图片xxx
  • 跳转到xxx页面
  • 页面向上滑动xxx
    ...

编辑一套常规操作步骤基本可以描述80%的系统特性场景。
定义步骤的目的是为了取得一定的结果,为了一种测试工具,cucumber如何告诉我们它是通过还是失败呢?
同大多数测试工具一样,cucumber使用异常来表达测试失败。一个完整的cucumber运行过程如下:


cucumber如何执行场景

在cucumber中,运行记过最终处于以下状态之一:

  • undefined
  • pending
  • failed
  • passed

未定义 undefined

表示cucumber无法匹配当前步骤的定义,即被标记为未定义。对于未定义的步骤,cucumber会在终端显示黄色的步骤定义说明。

待定 pending

对于只实现了一般的步骤,整个场景会停止,剩下的步骤会被跳过。cucumber依赖开发人员告知步骤定义是否完成,如果你的步骤定义还在开发中,可以将该步骤设置为pending,告诉cucumber步骤失败了,但是这是一种特殊意义的失败,步骤定义还在实现过程。
为什么会有pending这种状态呢?其实这也是一类常见的场景描述,我们在玩手游的时候,偶尔会看见部分功能尚未开放的指示,一为诱导用户等待更新,二为应用特性仍在开发中的提示。同理,pending状态的步骤定义成为了我们的待办事项 todo list。

失败的步骤

失败的步骤往往是因为抛出了异常,终端会显示红色标记并停止该场景。
失败的原因有两种:

  • 系统bug或步骤定义的error
  • 步骤定义中使用断言来校验系统状态,断言未通过

嵌套步骤

保证一个场景的每个步骤在同一个level,不要过度细化,避免过多的噪音。怎么理解这句话呢?我们来看一个例子:

Scenario: Driver the car
  Given I have a key of the car
  When I take the key
  And I use the key to start the car
  Then the car started
  Then I drive it out

在这个场景中,我们关注的细节在于,前置状态,触发状态和后续状态,这也是一个典型的cucumber场景描述。然而这里有太多关于触发状态(start the car)的噪音,以至于我们无法注意到真正重要的部分,过于细节化的,或命令式的场景存在风险。于是我们需要一类能抽象语义的步骤。

嵌套步骤重构

我们可以用一句简单的语义概括以上的触发状态(start the car)。

When I start the car

所以最终的场景描述应该如此:

Scenario: Driver the car
  Given I have a key of the car
  When I start the car
  Then I drive it out

是不是结构更加清晰,场景的主要部分更加突出了?场景的行为没有发生任何改变,只是特性的描述上升到了更高的抽象层次上了。

嵌套的危险

嵌套步骤是简易上手的,甚至在设计场景的过程中,会自然而然地想要抽象化一系列操作,对于开发人员来说,这等同于抽象一个通用的函数方法。有一位经验丰富的cucumber用户Andrew Premdas,分享了他的故事:

嵌套步骤不利于你成为一名更好的程序员,实现步骤定义所涉及的编程工作总的来说非常简单,每一次使用嵌套步骤,你就失去了一次和底层代码直接交互的机会,同时也失去了理解这些与系统对话的代码的机会。你变得越来越依赖于嵌套步骤,而不是伴随着新的场景持续学习并成长。随着你越来越多地使用嵌套步骤,这种依赖也会增加,而步骤定义的复杂度也会一起增长。
需要记住的重要一点是:你可以在每一个步骤定义的代码中使用提取方法这一重构技巧。这已选择永远比嵌套步骤更可取,因为发现、阅读及修改代码比处理步骤定义更容易。当你可以把一些方法抽取出来时,何必费劲折腾嵌套步骤呢?

实际场景汇总,我们嵌套得越多,实现场景就越难,而摆脱嵌套步骤可以让事情更加透明。

如何保证feature文件夹的条理性

很久以前cucumber作为工具诞生的时候,它的名字是RSpec Story Runner,那时候语言描述的测试使用story作为扩展名,为什么后来改成了feature呢?
用户故事是用来做计划的工具,每个故事包含可以划分优先级、构建、测试及发布的一点功能。故事发布后,我们不希望它在代码中留下痕迹,我们通常会重构以清理涉及,这样代码就可以重新接受用户的新行为,新故事。
我们也希望cucumber如此,特性描述应该描述系统今天的行为,它们不需要记录系统构建的历史,那是版本控制系统的事情!否则我们的feature会像下面这样:

features/
    story_0731_a.feature
    story_0807_b.feature
    story_0814_c.feature

也许只是针对同一类功能特性,我们生成了N个碎片化的特性,这无法成为系统文档,一个故事可能匹配了一个特性,另一个故事可能是将这个特性修改和优化。比如登录方式的改变,下单方式的改变。合理的方式应该是更新原有的特性,描述新的用户故事。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,335评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,895评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,766评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,918评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,042评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,169评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,219评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,976评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,393评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,711评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,876评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,562评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,193评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,903评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,699评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,764评论 2 351

推荐阅读更多精彩内容