Watir+cucumber+ruby

(一)什么是BDD?

BDD:Behavior Driven Development,行为驱动开发是一种敏捷软件开发的技术,它鼓励软件项目中的开发者、QA和非技术人员或商业参与者之间的协作。BDD最初是由Dan North在2003年命名,它包括验收测试和客户测试驱动等的极限编程的实践,作为对测试驱动开发的回应。在过去数年里,它得到了很大的发展。

2009年,在伦敦发表的"敏捷规格,BDD和极限测试交流"中,Dan North对BDD给出了如下定义:

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

 

(二)cucumber的工作原理

【转】行为驱动开发: Cucumber的目录结构和执行过程 

      Cucumber是Ruby世界的BDD框架,开发人员主要与两类文件打交到,Feature文件和相应的Step文件。Feature文件是以 feature为后缀名的文件,以Given-When-Then的方式描述了系统的场景(scenarios)行为;Step文件为普通的Ruby文 件,Feature文件中的每个Given/When/Then步骤在Step文件中都有对应的Ruby执行代码,两类文件通过正则表达式相关联。笔者在 用Cucumber+Watir做回归测试时对Cucumber工程的目录结构执行过程进行了研究。

安装好Cucumber后,如果在终端直接执行cucumber命令,得到以下输出:

输出结果表明:cucumber期待当前目录下存在名为features的子目录。建好features文件夹后,重新执行cucumber命令,输出如下:

Cucumber运行成功,但由于features文件夹下没有任何内容,故得到上述输出结果。

网上大多数关于Cucumber的教程都建议采用以下目录结构,所有的文件(夹)都位于features文件夹下。

Feature文件(如test.feature)直接位于features文件夹下,可以为每个应用场景创建一个Feature文件;与 Feature文件对应的Step文件(如test.rb)位于step_definitions子文件夹下;同时,存在support子文件夹,其下的 env.rb文件为环境配置文件。在这样的目录结构条件下执行cucumber命令,会首先执行env.rb做前期准备工作,比如可以用Watir新建浏 览器窗口,然后Cucumber将test.rb文件读入内存,最后执行test.feature文件,当遇到Given/When/Then步骤 时,Cucumber将在test.rb中搜索是否有相应的step,如果有,则执行相应的Ruby代码。

这样的目录结构只是推荐的目录结构,笔者通过反复的试验得出了以下结论:对于Cucumber而言,除了顶层的features文件夹是强制性的之 外,其它目录结构都不是强制性的,Cucumber将对features文件夹下的所有内容进行扁平化(flatten)处理和首字母排序。具体来 说,Cucumber在运行时,首先将递归的执行features文件夹下的所有Ruby文件(其中则包括Step文件),然后通过相同的方式执行 Feature文件。但是,如果features文件夹下存在support子文件夹,并且support下有名为env.rb的文件,Cucumber 将首先执行该文件,然后执行support下的其它文件,再递归执行featues下的其它文件。

比如有如下Cucumber目录结构:

为了方便记录Cucumber运行时的文件执行顺序,在features文件夹下的所有Ruby文件中加上以下代码:

puts File.basename(__FILE__)

此行代码的作用是在一个Ruby文件执行时输出该文件的名字,此时执行cucumber命令,得到以下输出(部分)结果:

上图即为Ruby文件的执行顺序,可以看出,support文件夹下env.rb文件首先被执行,其次按照字母排序执行c.rb和d.rb;接下 来,Cucumber将features文件夹下的所用文件(夹)扁平化,并按字母顺序排序,从而先执行a.rb和b.rb,而由于other文件夹排在 step_definitions文件夹的前面,所以先执行other文件夹下的Ruby文件(也是按字母顺序执行:先f.rb,然后g.rb),最后执 行step_definitions下的e.rb。

当执行完所有Ruby文件后,Cucumber开始依次读取Feature文件,执行顺序也和前述一样,即: a.feature --> b.feature --> c.feature

笔者还发现,这些Ruby文件甚至可以位于features文件夹之外的任何地方,只是需要在位于features文件夹之内的Ruby文件中require一下,比如在env.rb中。

(三)

【转载】10分钟学会 Cucumber + Watir 自动化测试框架

分类: Watir 2012-03-21 09:32 1101人阅读 评论(0) 收藏 举报

测试searchthoughtworksgooglebrowsermodule

 计你早已厌烦了成百上千遍的网页点击测试,至少之前的我是这样的,那么,让自己的web测试自动化吧,本文使用Cucumber + Watir来完成自动化测试,从最简单例子入手,一步一步重构成一个完整的自动化测试框架。

   

(一)Cucumber和Watir的关系

    Cucumber和Watir可以没有任何关系,Cucumber只是一个BDD框架,而Watir只是一个Web Driver而已,两者的共同点是均属于Ruby世界。

   

(二)单独使用Cucumber

    关于Cucumber的执行过程请参考笔者的另一篇文章:行为驱动开发: Cucumber的目录结构和执行过程 。

    由于Cucumber和Watir没有必然联系,因此两者均可单独使用,下面就让我们用Cucumber来写一个非常简单的单元测试。 定义一个需要测试的Calculator类如下:

1 class Calculator

2 def add num1, num2

3 num1+num2

4 end

5 end

复制代码

    用于测试Calculator类的add方法的feature文件如下:

1 Feature: Unit test for Calculator

2

3 Scenario: Add two numbers

4 Given I have a calculator created

5 When I add '3' and '5'

6 Then I should get the result of '8'

复制代码

    对应的step文件为:

1 require File.join(File.dirname(__FILE__), "../calculator")

2 require 'rspec'

3

4 Given /^I have a calculator created$/ do

5 @calculator = Calculator.new

6 end

7

8 When /^I add '([^"]*)' and '([^"]*)'$/ do |num1, num2|

9 @result = @calculator.add(num1.to_i, num2.to_i)

10 end

11

12 Then /^I should get the result of '([^"]*)'$/ do |expected_result|

13 @result.should == expected_result.to_i

14 end

复制代码

    在以上的step文件中,第1,2行分别require了自定义的Calculator类和rspec(用于assertion,参考第13行的 "should"), 第5行新建了一个@calculator实例变量,第9行完成两个数相加(3+5),第13行为测试断言。运行cucumber命令,输出结果如下:

1 Feature: Unit test for Calculator

2

3 Scenario: Add two numbers # features/Calculator.feature:4

4 Given I have a calculator created # features/step_definitions/calculator_step.rb:4

5 When I add '3' and '5' # features/step_definitions/calculator_step.rb:8

6 Then I should get the result of '8' # features/step_definitions/calculator_step.rb:12

7

8 1 scenario (1 passed)

9 3 steps (3 passed)

10 0m0.002s

复制代码

    测试成功,没有看到任何Watir的影子。

   

(三)单独使用Watir

    听说有非常fashionable的office lady用Watir来完成日常例行并且繁琐的网页点击工作的(当然不是测试),听说而已,但是Watir的确可以完成诸如此类的网页模拟操作,接下类我 们就用Watir来完成google搜索功能,新建watir_google.rb文件并加入以下内容:

1 require 'watir-webdriver'

2 browser = Watir::Browser.new :chrome

3 browser.goto "www.google.com/"

4 browser.text_field(:name => "q").set "ThoughtWorks"

5 browser.button(:name => "btnG").click

复制代码

  当执行到第2行时,一个浏览器窗口会自动打开,之后访问google主页(第3行),设置搜索关键词"ThoughtWorks",最后点击搜索按钮,单独运行Watir成功,没有任何Cucumber的影子。

   

(四)用Cucumber+Watir写自动化测试

    由上文可知,Cucumber只是用接近自然语言的方式来描述业务行为,而Watir则只是对人为操作网页的模拟。当使用Cucumber+Watir 实现自动化测试时,通过正则表达式匹配将Cucumber的行为描述与Watir的网页操作步骤耦合起来即可。同样以Google搜索为例,搜索关键字 后,我们希望获得搜索结果,先用Cucumber完成搜索行为描述:

1 Feature:Google search

2 Scenario: search for keyword

3 Given I am on google home page

4 When I search for 'ThoughtWorks'

5 Then I should be able to view the search result of 'ThoughtWorks'

复制代码

   对应的Watir代码如下:

1 require "rubygems"

2 require "watir-webdriver"

require 'rspec'

4 Given /^I am on google home page$/ do

5 @browser = Watir::Browser.new :chrome

6 @browser.goto("www.google.com")

7 end

8

9 When /^I search for '([^"]*)'$/ do |search_text|

10 @browser.text_field(:name => "q").set(search_text)

11 @browser.button(:name => "btnK").click

12 end

13

14 Then /^I should be able to view the search result of '([^"]*)'$/ do|result_text|

15 @browser.text.should include(result_text)

16 end

复制代码

    运行cucumber,一个新的浏览器被打开,显示结果与(三)中相同。

(五)自动化测试的设计模式:Page对象

   在上面的例子中,我们在所有的step中均直接对@browser对象进行操作,对于这样简单的例子并无不妥,但是对于动则几十个甚至上百个页面的网站来 说便显得过于混乱,既然要面向对象,我们就希望将不同的页面也用对象来封装,于是引入Page对象,既可完成对页面的逻辑封装,又实现了分层重用。此时位 于high-level的Cucumber文件无需变动,我们只需要定义一个Page对象来封装Google页面(google-page.rb):

1 require "rubygems"

2 require "watir-webdriver"

3 require "rspec"

4

5 class GooglePage

6 def initialize

7 @browser = Watir::Browser.new :chrome

8 @browser.goto("www.google.com")

9 end

10

11 def search str

12 @browser.text_field(:name => "q").set(str)

13 @browser.button(:name => "btnK").click

14 end

15

16 def has_text text

17 @browser.text.should include(text)

18 end

19 end

复制代码

   相应的step文件需要做相应的修改:

1 require File.join(File.dirname(__FILE__), "google-page")

2

3 Given /^I am on google home page$/ do

4 @page = GooglePage.new

5 end

6

7 When /^I search for '([^"]*)'$/ do |search_text|

8 @page.search search_text

9 end

10

11 Then /^I should be able to view the search result of '([^"]*)'$/ do|result_text|

12 @page.has_text result_text

13 end

复制代码

     运行cucumber,一个新的浏览器被打开,显示结果与(三)中相同。

(六)加入角色用户

   既然是行为驱动,既然是模拟用户实际操作,那么直接对Page对象进行操作也显得不够了,于是我们引入了角色用户User对象,对于拥有多种用户角色的网 站来说特别实用。加入User对象之后,step文件中不再出现对Page对象的直接引用,而是在User对象的行为方法中进行引用,定义User对象如 下(user.rb):

1 require File.join(File.dirname(__FILE__), "google-page")

2

3 class User

4 def initialize

5 @browser = Watir::Browser.new :chrome

6 end

7

8 def visit_google

9 @page = GooglePage.new(@browser)

10 end

11

12 def search_text text

13 @page.search text

14 end

15

16 def assert_text_exist text

17 @page.has_text text

18 end

复制代码

   feature文件保持不变,在step文件用User代替Page:

1 require File.join(File.dirname(__FILE__), "user")

2

3 Given /^I am on google home page$/ do

4 @user = User.new

5 @user.visit_google

6 end

7

8 When /^I search for '([^"]*)'$/ do |search_text|

9 @user.search_text search_text

10 end

11

12 Then /^I should be able to view the search result of '([^"]*)'$/ do|result_text|

13 @user.assert_text_exist result_text

14 end

复制代码

   运行cucumber,一个新的浏览器被打开,显示结果与(三)中相同。 

   对于拥有多个用户角色的网站,比如又customer,administrator等,可分别对这些角色定义相应的对象,再在step文件中应用这些角色对象即可。

   

  (七)用ruby的Module来封装不同的行为功能

     对于单个用户来说,比如网上购物网站的customer,既要购物操作,又要能修改自己的profile,此时为了对这些不同的逻辑功能进行组织,可引入 ruby中的Module来进行封装,即将costomer的不同行为功能模块封装在不同的module中,然后在customer对象中include 这些Module。为简单起见,依然用Google搜索来进行演示,此时可将搜索功能加入到Module中,定义搜索module(search- behavior.rb)如下:

1 module SearchBehavior

2

3 def visit_google

4 @page = GooglePage.new(@browser)

5 end

6

7 def search_text text

8 @page.search text

9 end

10

11 def assert_text_exist text

12 @page.has_text text

13 end

14

15 end

复制代码

    在User对象中include该Module:

1 require File.join(File.dirname(__FILE__), "search-behavior")

2 class User

3 include SearchBehavior

4 def initialize

5 @browser = Watir::Browser.new :chrome

6 end

复制代码

  对step文件和feature文件均不用修改,运行cucumber,一个新的浏览器被打开,显示结果与(三)中相同。

(八)总结

   我们可以在Cucumber对应的step文件中直接访问Watir的API,这样的确也能达到测试目的,但这样的缺点在于缺少设计,于是我们引入 Page对象来封装不同的页面,引入用户角色管理不同的用户行为,再引入Module来组织不同的功能模块,最后重构成了一个简单实用的自动化测试框架。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值