(整理)自动化测试(Cucumber+Watir)

为什么要实施自动化测试?

  • ##### 应用系统日趋复杂的客观要求
    一个不可避免的问题是,应用系统变得日趋复杂,并且造成了更大的风险。测试消耗的成本越来越高,花费的时间也越来越长。而成本与时间是有限的。为了在有限的成本和时间范围内,控制发布的软件产品质量,测试人员被要求在尽量短的时间内对软件进行足够的测试。
  • ##### 避免重复测试的主观要求
    迭代式开发过程:目前的软件开发或多或少的使用了迭代式开发过程,这就导致了我们需要进行一轮又一轮的测试。
    回归测试:为了检查软件版本是否正确,或者当发现软件中出现一个或多个以前曾经被修复的缺陷时,不可避免的需要进行回归性的测试。

自动化测试实施失败的因素?

  1. 期望值过高。就像管理人员要求完全测试一样,期望100%的测试自动化,也同样是一个不显示的需求。
  2. 自动化的收益和成本:
    成本 = 用例的开发 + 用例的维护
    收益 = 重复运行次数 + 节约的时间
    收益和成本

自动化测试的成长过程

Testing often begins as freestyle, expands toward scripted.
测试总是从自由式的探索开始,朝着脚本化方向扩张。
脚本化

自动化测试的应用时机

应用时机

冒烟测试
这一术语源自硬件行业。对一个硬件或硬件组件进行更改或修复后,直接给设备加电。如果没有冒烟,则该组件就通过了测试。在软件中,“冒烟测试”这一术语描述的是在将代码更改嵌入到产品的源树中之前对这些更改进行验证的过程。在检查了代码后,冒烟测试是确定和修复软件缺陷的最经济有效的方法。冒烟测试设计用于确认代码中的更改会按预期运行,且不会破坏整个版本的稳定性。

回归测试
回归测试是指修改了旧代码后,重新进行测试以确认修改没有引入新的错误或导致其他代码产生错误。自动回归测试将大幅降低系统测试、维护升级等阶段的成本。回归测试作为软件生命周期的一个组成部分,在整个软件测试过程中占有很大的工作量比重,软件开发的各个阶段都会进行多次回归测试。在渐进和快速迭代开发中,新版本的连续发布使回归测试进行的更加频繁,而在极端编程方法中,更是要求每天都进行若干次回归测试。因此,通过选择正确的回归测试策略来改进回归测试的效率和有效性是很有意义的。

重头戏:测试方案设计

  1. 自动化测试的功能方案设计的流程:
    操作对象→对象属性→功能实现→结果验证
  2. 自动化测试的功能方案设计操作用例图:
    用例图

Cucumber

开源项目地址:github/cucumber-ruby

Installation

you can run:

gem install cucumber-rails -v 0.3.2
// gem install cucumber  

If you are using Bundler, just add it to your Gemfile:

gem "capybara", "1.1.1"
gem "cucumber", "1.1.0"
gem "cucumber-rails", "0.3.2"  

Then initialize a features directory:

cucumber --init   

Running

To see the full list of options:

cucumber --help    

Otherwise, to run all features:

cucumber   

If working on a fresh Rails project, first set up the (empty) database:

rake db:migrate  

(Otherwise Cucumber fails with the error no such file to load – YourProjectName/db/schema.rb.)

Then run the features:

rake cucumber

Watir WebDriver

开源项目地址:github/watir
API:api

浏览器支持:

Firefox, Chrome, IE,Safari

I could make uo lots of quotes about how good it is, but I don’t need to, it’s that good.

Getting Started

// gem install watir-webdriver  
gem 'watir', '~> 6.7'
gem install watir

Getting Going

require 'watir-webdriver'
b = Watir::Browser.new
b.goto 'bit.ly/watir-webdriver-demo'
b.text_field(:id => 'entry_1000000').set 'your name'
b.select_list(:id => 'entry_1000001').select 'Ruby'
b.select_list(:id => 'entry_1000001').selected? 'Ruby'
b.button(:name => 'submit').click
b.text.include? 'Thank you'  

自动化测试

Cucumber和Watir的关系

Cucumber是一个BDD框架;Watir是一个Web Driver。两者都是由Ruby编写的。

单独使用Cucumber

对于Cucumber的执行过程可以参考文章:行为驱动开发:Cucumber的目录结构和执行过程
由于Cucumber和Watir没有必然联系,因此两者均可单独使用,下面就让我们用Cucumber写一个简单的单元测试。定义一个需要测试的Calculator类如下:

class Calculator
  def add num1, num2
    num1 + num2
  end
end  

class Calculator
  def add num1, num2
    num1 + num2
  end
end  

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

Feature: Unit testforCalculator

Scenario: Add two numbers
Given I have a calculator created
When I add '3' and '5'
Then I should get the result of '8'  

对应的step文件为:

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

Given /^I have a calculator created$/ do
  @calculator = Calculator.new
end

When /^I add '([^"]*)' and '([^"]*)'$/ do |num1, num2|
  @result = @calculator.add(num1.to_i, num2.to_i)
end

Then /^I should get the result of '([^"]*)'$/ do |expected_result|
  @result.should == expected_result.to_i
end  

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

Feature: Unit testforCalculator

Scenario: Add two numbers             # features/Calculator.feature:4
Given I have a calculator created   # features/step_definitions/calculator_step.rb:4
WhenI add '3' and '5'              # features/step_definitions/calculator_step.rb:8
ThenI should get the result of '8' # features/step_definitions/calculator_step.rb:12

1 scenario (1 passed)
3 steps (3 passed)
100m 0.002s  

单独使用Watir

接下来用Watir完成Google搜索功能,新建watir_google.rb文件并加入以下内容:

require 'watir_webdriver'  
browser = Watir::Browser.new :chrome  
browser.goto "www.google.com/"  
browser.text_filed(:name => "q").set "Why I am so handsome ?"  
browser.button(:name => "btnG").click  

当执行到第2行时,一个浏览器窗口会自动打开,之后访问google主页(第三行),设置搜索关键字“why I am so handsome ?”,最后点击搜索按钮,单独运行Watir成功。

用Cucumber + Watir写自动化测试

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

Feature:GoogleSearch  
Scenario: search for keyword  
Given I am on google home page  
When I search for 'why I am so handsome ?'  
Then I should be able to view the search result of 'why I am so handsome ?'  

对应的Watir代码如下:

require "rubygems"  
require "watir-webdriver"  
require "rspec"  
Given /^I am on google home page$/ do  
  @browser = Watir::Browser.new :chrome  
  @browser.goto("www.google.com")  
end  


When/^I search for'([^"]*)'$/ do |search_text|
  @browser.text_field(:name => "q").set(search_text)
  @browser.button(:name => "btnK").click
end

Then /^I should be able to view the search result of '([^"]*)'$/ do |result_text|
  @browser.text.should include(result_text)
end  

运行cucumber,一个新的浏览器被打开,显示结果测试通过

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

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

require "rubygems"  
require "watir-webdriver"  
require "rspec"  

class GooglePage  
  def initialize  
    @browser = Watir::Browser.new :chrome  
    @browser.goto("www.google.com")  
  end  

  def search str  
    @browser.text_filed(:name =>   "q").set(str)  
    @browser.button(:name => "btn").click  
  end  

  def has_text text  
    @browser.text.should include(text)  
  end
end  

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

require File.join(File.dirname(_FILE_), "google-page")  
Given /^I am on google home page$/ do  
  @page.GooglePage.new  
end  

When /^I search for '([^"]*)'$/ do |search_text|  
  @page.search search_text  
end  

Then /^I should be able to view the search result of '([^"]*)'$/ do |reault_text|  
  @page.has_text result_text  
end  

运行cucumber,一个新的浏览器被打开,显示结果与上次结果相同。

加入用户角色

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

require File.join(File,dirname(_FILE_), "google-page")  
class User  
  def initialize  
    @browser = Watir::Browser.new :chrome  
  end  

  def visit_google  
    @page = GooglePage.new(@browser)  
  end  

  def search_text text  
    @page.search text  
  end  

  def assert_text_exist text  
    @page.has_text text  
  end  
end  

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

require File.join(File.dirname(_FILE_), "user")  
Given /^I am on google home page$/ do  
  @user = User.new  
  @user.visit_google  
end  

When /^I search for '([^"])'$/ do |search_text|  
  @user.search_text search_text  
end  

Then /^I should be able to view the search result of '([^"])'$/ do |result_text|  
  @user.assert_text_exist result_text  
end  

运行cucumber,一个新的浏览器被打开,显示结果与上次结果相同。
对于拥有多个用户角色的网站,比如有admin,user等,可分别对这些角色定义相应的对象,再在step文件中应用这些对象即可。

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

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

module SearchBehavior  
  def visit_google  
    @page = GooglePage.new(@browser)
  end  

  def search_text text  
    @page.search text  
  end  

  def assert_text_exist text  
    @page.has_text text  
  end
end  

在User对象中include这个Module:

require File.join(File.dirname(__FILE__), "search-behavior")  
class User  
require 'search_behavior'  
  def initialize  
    @browser = Watir::Browser.new :chrome  
  end
end  

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

总结

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

Web对象的识别-Watir-WebDriver

简介

input-输入框  
button-按钮  
select-下拉框  
link-链接  
click-点击  
radio-单选  
checkbox-多选  
send_key :enter-模拟键盘  

页面元素的捕获

页面元素
  • attribute_value
    获取当前空间的属性

    Value = ie.link(:id=>'xxx').attribute_value("href")
    
  • rand_select
    随机选择select list中的某一项

    ie.select_list(:name=>’’).rand_select
    
  • popupwin
    端架弹窗上的‘确定’按钮

    ie.popupwin.button(:name=>"确定").click
    
  • sikuli_image
    点击图片控件

    ie.sikuli_image(:image=>"1.png").click  
    
    ie.sikuli_image(:image=>"1.png;2.png").click#可以指定多张图片来识别
    
  • double_click
    双击事件

    ie .sikuli_image(:image=>"1.png").double_click
    
  • right_click
    右击事件

  • exist?
    判断用户元素是否存在

    edit = ie.text_field(:name,”username”)
    if edit.exist?() #The highlighted
    edit.flash
    ie.text_field(:name, “password”).set(pwd)
    ie.button(:class, “x-login-submit”).click
    end
    end

  • Text Fields

    require 'watir-webdriver'
    
    b = Watir::Browser.start 'bit.ly/watir-webdriver-demo'
    
    t = b.text_field :id => 'entry_0'
    
    t.exists?
    
    t.set 'your name'
    
    t.value
    
  • Select LIsts - Combos

    require 'watir-webdriver'
    
    b = Watir::Browser.start 'bit.ly/watir-webdriver-demo'
    
    s = b.select_list :id => 'entry_1'
    
    s.select 'Ruby'
    
    s.selected_options
    
    # 返回选中的选项  
    puts b.select(:name, 'sex').selected_options  
    
  • Radios

    require 'watir-webdriver'
    
    b = Watir::Browser.start 'bit.ly/watir-webdriver-demo'
    
    r = b.label(:text => 'What is ruby?').parent.radio :value => 'A gem'
    
    r.exists?
    
    r.set
    
    r.set?
    
  • Checkboxes

    require 'watir-webdriver'
    
    b = Watir::Browser.start 'bit.ly/watir-webdriver-demo'
    
    c = b.label(:text => 'What versions of ruby?').parent.checkbox :value => '1.9.2'
    
    c.exists?
    
    c.set
    
    c.set?
    
    # 选择checkbox  
    b.checkbox(:name, 'check_me').set true 
    # 清除选择  
    b.checkbox(:name, 'check_me').set false 
    
  • Buttons

    require 'watir-webdriver'
    
    b = Watir::Browser.start 'bit.ly/watir-webdriver-demo'
    
    btn = b.button :value, 'Submit'
    
    btn.exists?
    
    btn.click
    
  • Links

    require 'watir-webdriver'
    
    b = Watir::Browser.start 'bit.ly/watir-webdriver-demo'
    
    l = b.link :text => 'Google Docs'
    
    l.exists?
    
    l.click
    
  • Div & Spans

    require 'watir-webdriver'
    
    b = Watir::Browser.start 'bit.ly/watir-webdriver-demo'
    
    d = b.div :class => 'ss-form-desc ss-no-ignore-whitespace'
    
    d.exists?
    
    d.text
    
    s = b.span :class => 'ss-powered-by'
    
    s.exists?
    
    s.text  
    

实例

按钮
ie.button(:name=>"",:id=>"",:index=>n,:type=>"").click    

ie.button(:name=>"",:id=>"",:index=>n,:type=>"").doclick
输入框
ie.text_field(:name=>"").set "变量"   

ie.text_field(:name=>"").value 取text_field值不是用text而是value!
下拉框
ie.select_list(:name=>"").select "下拉框值"  

ie.select_list(:name=>"").select "#1" #表示第一项内容  

ie.select_list(:name=>"").rand_select  

ie.select_list(:name=>"").getSelectedItems|getAllContents->返回Array
单选框
ie.radio(:id=>"",:name=>"",:index=>n).set(选中当前radio)  

ie.radio(:id=>"",:name=>"",:index=>n).clear(取消选中当前radio)

ie.div(:class=>"iradio_minimal-blue checked").radios[1]
复选框
ie.check_box(:id=>"",:name=>"",:index=>n).set(true|false)(true表示选中,false表示不选中)  

ie.check_box(:id=>"",:name=>"",:index=>n).clear(取消选中当前checkbox)
链接
ie.link(:text=>"").click/doclick  

ie.link(:text=>"").href(返回当前link指向的链接)
cell (TD标签,用时一般需要先找到上层控件如table、div等)
ie.table(:class=>"",:index=>n).cell(:class=>"",:index=>n).text  

ie.table(:index=>n).rows 行  列 .text (行、列从1开始)  

ie.div(:class=>"",:index=>n).cell(:class=>"",:index=>n).text
span
ie.table(:id=>"").span(:class=>"").text
弹出框
ie.popupwin.get_static_text (返回当前提示框的文本)   

ie.popupwin.button(:name=>"确定").click/doclick (前一个点击按钮必须用doclick)   

ie.file_dialog(:index=>1/2).set_file(file_path_download,true) (保存文件的弹出窗口)  
alert
if b.alert.exists?  
    puts "ok"
else
    puts "no"
end

puts b.alert.text 

#b.alert.ok 
b.alert.close  

b.close  
图片
ie.image(:src=>/word3a_nor.gif/).click/doclick
back

后退

ie.back
forward

前进

ie.forward
refresh

刷新页面

ie.refresh

在Watir-WebDriver中处理frame是非常简单的,就跟处理其他页面元素一样:

b.frame(:id => "content_ifr").send_keys "hello world"
素材来源:
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Cucumber是一种行为驱动开发(BDD)工具,它结合了自然语言和自动化测试,用于编写可执行的规范文档。它使用Gherkin语言来描述应用程序的行为,并将这些描述转化为可执行的测试代码。 Cucumber的核心思想是通过定义特定的场景和步骤来描述应用程序的行为。这些场景和步骤以Gherkin语言的格式编写,例如: ``` Feature: 用户登录 用户可以通过用户名和密码登录系统 Scenario: 正确的用户名和密码 Given 用户打开登录页面 When 用户输入正确的用户名和密码 And 用户点击登录按钮 Then 用户成功登录系统 Scenario: 错误的用户名和密码 Given 用户打开登录页面 When 用户输入错误的用户名和密码 And 用户点击登录按钮 Then 用户收到错误提示信息 ``` 上述示例中,`Feature`定义了一个功能,`Scenario`定义了一个具体的场景,`Given`、`When`、`Then`等关键词定义了具体的步骤。 Cucumber支持多种编程语言,如Java、Ruby、JavaScript等。你可以使用相应的Cucumber库来编写测试代码,并将Gherkin语言的描述与测试代码关联起来。当运行测试时,Cucumber会解析Gherkin语言的描述,并执行相应的测试代码。 Cucumber的优点包括: 1. 提供了一种可读性强的测试文档形式,使得非技术人员也能理解和参与测试过程。 2. 通过自然语言描述测试场景,减少了测试用例的维护成本。 3. 支持多种编程语言和测试框架,灵活性高。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值