(转自:http://www.cnblogs.com/jarodzz/archive/2012/07/02/2573014.html)
第一次看到Cucumber和BDD(Behavior Driven Development, 行为驱动开发),是在四年前。那时才開始工作,对软件測试工具相当着迷。仅仅要是开源的、免费的,我就一定要下载,安装,试用。有的工具用途单一、好懂(如Jmeter,Watir);有的工具,则涉及到一些软件领域的独有概念,不好懂,(如STAF,Cucumber)。好懂的,我上手、试用、推广,不亦乐乎;不好懂的,就仅仅能丢在一边,这里面就包含Cucumber。
再次看到Cucumber,已是两年前。我对软件开发的理解也深了些,这一看,可真是个好东西。之后我与Cucumber间发生的故事,稍后慢慢向大家交代。这开篇的第一章,我想献给如当年的我一样,偶然见到了Cucumber和BDD,却不明所以将之丢在一边的家伙们。
初闻Cucumber的人,第一件事一定是来到Cucumber的首页,第一眼看到的一定是
非常不幸的是,这六张图不太好懂。由于它们依照BDD的流程来编写的。为了让它们好懂些,我们抛开BDD,採用传统的软件开发模型(设计->编码->測试)来看它。传统流程例如以下:
为了便于大家理解,我试着改动了一些。
class
Calculator
def
push(n)
#记数
@args
||= []
#初始化空数组
@args
<< n
end
def
sum()
#返回全部数字和
sum =
0
@args
.
each
do
|i|
sum += i
end
@result
= sum
end
def
result
@result
end
end
|
计算器Calculator提供两个功能: 记数push;加和sum。push将数字一一记录在@args数组中;sum则将全部@args数组中的数字累加得和,存入@result中。写完了被測系统,我们来编写測试用例。
原图中的英文描写叙述,被我翻译成了中文。:
Feature: 计算器
Scenario: 两数相加
Given 我有一个计算器
And 我向计算器输入
50
And 我向计算器输入
70
When 我点击累加
Then 我应该看到结果
120
|
支持中、英等自然语言,是Cucumber的特点之中的一个。在Cucumber的帮助文档里,声明它支持包含中文简体、繁体中文、日文、韩文和英文在内的45种语言。
注意:我并未将全部英文都翻译成中文,而是留下了几个keyword:
它们的含义与原有自己主动化測试工具中的概念同样,类比方下:
Cucumber | Unit Test |
---|---|
Feature (功能) | test suite (測试用例集) |
Scenario(情景) | test case (測试用例) |
Given(给定) | setup(创建測试所需环境) |
When(当) | test(触发被測事件) |
Then(则) | assert(断言,验证结果) |
Cucumber放弃了原有的keyword,而选择了左边五种,仅仅是为了更加流畅地支持自然语言。使用Cucumber的keyword,创建了測试用例,接下来,要怎样使用Cucumber来执行它呢?
在一台安装好Cucumber的机器上,执行上述測试用例,便能够看到下列输出:
Feature: 计算器
Scenario: 两数相加
# features/calculator.feature:3
Given 我有一个计算器
# features/calculator.feature:4
And 我向计算器输入
50
# features/calculator.feature:5
And 我向计算器输入
70
# features/calculator.feature:6
When 我点击累加
# features/calculator.feature:7
Then 我应该看到结果
120
# features/calculator.feature:8
1
scenario (
1
undefined)
5
steps (
5
undefined)
0m0.005s
You can implement step definitions
for
undefined steps with these snippets:
Given /^我有一个计算器$/
do
pending
# express the regexp above with the code you wish you had
end
Given /^我向计算器输入(\d+)$/
do
|arg1|
pending
# express the regexp above with the code you wish you had
end
When /^我点击累加$/
do
pending
# express the regexp above with the code you wish you had
end
Then /^我应该看到结果(\d+)$/
do
|arg1|
pending
# express the regexp above with the code you wish you had
end
|
Cucumber首先输出的是測试用例的描写叙述,然后3行总结性地输出:本功能(Feature)有1个情景(1 scenario);5个步骤(5 steps),所有5个步骤均没有定义(undefined);执行耗时0.005秒。这里出现了两个新名词:步骤(steps)和步骤定义(step definitions)。在Cucumber中,以keywordGiven, And, When, Then开头的每一行,为一个步骤。在两数相加的情景中,一共同拥有5行。因此,结果显示:5个步骤。
怎样定义一个步骤,在Cucumber的执行结果中也给出了具体的办法。在3行总结性输出后,紧接着便是:You can implement…即:你能够使用以下的代码段实现步骤定义,然后是4个小的代码段。这些代码段,便是Cucumber按照情境中我们使用的5个步骤,帮助我们生成的步骤定义框架。每一个框架都将内容部分空白出来,等待填充。以下,我们来进行步骤定义。
我们按照图2的样子,向中文步骤中填入代码,例如以下:
Given /^我有一个计算器$/
do
@c
= Calculator.
new
end
Given /^我向计算器输入(\d+)$/
do
|num|
@c
.push(num.to_i)
end
When /^我点击累加$/
do
@c
.sum
end
Then /^我应该看到结果(\d+)$/
do
|result|
@c
.result.should == result.to_i
end
|
步骤定义的过程,就是向代码段——步骤定义框架——中填入代码的过程,即:用代码来描写叙述你期望的,该步骤应该运行的动作。完整的步骤定义是一个函数,它:
由于有了正則表達式的匹配,5个步骤仅须要4个步骤定义。“我向计算器输入50、70”两个步骤,都能够用“我向计算器输入(\d+)”一个正則表達式来描写叙述。匹配值被自己主动提取出来作为參数,传入代码。注意:全部匹配值,即參数,都是以字符串的形式传递,因此,我增加了num.to_i 与 result.to_i,将得到的字符串转为整形。步骤定义完毕,再次运行Cucumber。屏幕将会显示一片绿色。
步骤定义完毕后,再次执行Cucumber。Cucumber会找到步骤定义,并依照其代码去执行。结果例如以下:
Feature: 加法
Scenario: 两数相加
# features/calculator.feature:3
Given 我有一个计算器
# features/step_definitions/a.rb:2
And 我向计算器输入
50
# features/step_definitions/a.rb:6
And 我向计算器输入
70
# features/step_definitions/a.rb:6
When 我点击累加
# features/step_definitions/a.rb:10
Then 我应该看到结果
120
# features/step_definitions/a.rb:14
1
scenario (
1
passed)
5
steps (
5
passed)
0m0.003s
|
步骤定义被我保存在目录step_definitions下的a.rb其中。步骤定义所在文件与起始行数,被打印在每一个步骤结尾,以方便查找和改动。最后,Cucumber总结性地输出执行结果:1个情景,5个步骤,所有通过。
为了让这个已经十分简单的计算器产生bug,我仅仅好将它改错为:
class
Calculator
def
sum()
sum =
0
@args
.
each
do
|n|
sum = n
#此处原为:sum += n
end
@result
= sum
end
end
|
再次执行Cucumber,结果为:
Feature: 加法
Scenario: 两数相加
# features/calculator.feature:3
Given 我有一个计算器
# features/step_definitions/a.rb:2
And 我向计算器输入
50
# features/step_definitions/a.rb:6
And 我向计算器输入
70
# features/step_definitions/a.rb:6
When 我点击累加
# features/step_definitions/a.rb:10
Then 我应该看到结果
120
# features/step_definitions/a.rb:14
expected:
120
got:
70
(using ==) (RSpec::Expectations::ExpectationNotMetError)
./features/step_definitions/a.rb:
15
:in
`/^我应该看到结果(\d+)$/'
features/calculator.feature:
8
:in
`Then 我应该看到结果
120
'
Failing Scenarios:
cucumber features/calculator.feature:
3
# Scenario: 两数相加
1
scenario (
1
failed)
5
steps (
1
failed,
4
passed)
0m0.004s
|
失败的步骤是用红色标示出来的。在最后一个步骤中,Cucumber期待的结果为120,但得到的是70。注意:失败的情景列表(Failing Scenarios)里列出的是:“两数相加”这个情景所在的文件与起始行数。这是由于一个功能文件内,可能含有多个情景,这样的输出能够便于找到出错的情景。
接下来的总结性结果为:1个情景失败(1 failed),5个步骤中,4个通过,1个失败。
作为自己主动化測试工具的Cucumber,就介绍到这里。
在继续之前,我们先回想一下本章内容。