Web应用自动化验收工具——Selenium系列预研

2010-12-30  付民 

1.Selenium工具简介

Selenium是ThoughtWorks公司开发的一套基于WEB应用的验收测试工具,直接运行在浏览器中,模拟客户操作。它抽象出一系列命令来模块用户操作,比如open命令表示打开一个URL,click命令表示点击某个按钮。Selenium实际上将这些命令转化成实际的HTTP请求在浏览器中运行。本系列现在主要包括以下4款:

   1. Selenium Core,它的优点是编写测试案例简单,并且支持绝大多数的浏览器,但缺点也同样明显,Selenium Core需要远程安装,Selenese 语言也限制了复杂案例的可能性,并且没有良好的外部扩展,这是些都会是致命的问题。
   2. Selenium Grid:允许同时并行地、在不同的环境上运行多个测试任务,极大地加快Web 应用的功能测试。
   3. Selenium IDE :支持并且只支持Firefox浏览器,属于Firefox的一个插件,支持的浏览器太少,而依附于Firefox 也不便于日后开展自动化测试,但是,它的录制快捷好用!并且有代码转换功能,可以把Selenium 语言测试用例转为C#,Java,PHP,Ruby,Prel,Groovy,Python等语言的测试案例,我建议使用Selenium IDE + FireBug 进行测试案例的编写,然后转为其他语言的测试用例后,再调用Selenium RC运行测试用例。
   4. Selenium RC(Remote Control) 是本人推荐使用的工具,它支持很多浏览器,可以使用C#,Java 等语言编写测试案例,易于维护,同时提供了很好的扩展性,所以接下来将针对Selenium RC 作为默认的测试工具进行介绍。

所以这里建议采用Selenium IDE + Selenium RC + Firebug组合搭建Web应用自动化验收测试。
2.Selenium-IDE安装和使用

安装

   1. Selenium官网(http://seleniumhq.org/)下载Selenium-IDE作为Firefox的插件进行安装

使用

1.Firefox工具栏,打开Selenium-IDE插件,如下图:



2.选择插件界面中右上角红色录制按钮(开始录制、停止录制都是此按钮),如下图,这里录制登陆集中管理工具的过程。




3.录制完成后,点击回放按钮可以对刚刚录制的脚本进行回放,这里可以调整回放速度。

4.可以将录制的脚本转换成C#,Java,PHP,Ruby,Prel,Groovy,Python等语言,这里选择Java,如下图:




转换后代码如下:

Java代码 复制代码
  1. package com.example.tests;   
  2.   
  3. import com.thoughtworks.selenium.*;   
  4. import java.util.regex.Pattern;   
  5.   
  6. public class MasterLogin extends SeleneseTestCase {   
  7.     public void setUp() throws Exception {   
  8.         setUp("http://change-this-to-the-site-you-are-testing/""*chrome");   
  9.     }   
  10.     public void testUntitled 2() throws Exception {   
  11.         selenium.open("/gm/login.jsf");   
  12.         selenium.type("j_username""tongweb");   
  13.         selenium.type("j_password""tongweb");   
  14.         selenium.click("j_security_check");   
  15.         selenium.waitForPageToLoad("30000");   
  16.     }   
  17. }  
package com.example.tests; import com.thoughtworks.selenium.*; import java.util.regex.Pattern; public class MasterLogin extends SeleneseTestCase { public void setUp() throws Exception { setUp("http://change-this-to-the-site-you-are-testing/", "*chrome"); } public void testUntitled 2() throws Exception { selenium.open("/gm/login.jsf"); selenium.type("j_username", "tongweb"); selenium.type("j_password", "tongweb"); selenium.click("j_security_check"); selenium.waitForPageToLoad("30000"); } }


5.上面转换的代码可以稍加修改便可配合RC使用,修改后代码如下:

Java代码 复制代码
  1.  package com.example.tests;   
  2.   
  3. import com.thoughtworks.selenium.*;   
  4. import java.util.regex.Pattern;   
  5.   
  6. public class MasterLogin extends SeleneseTestCase {   
  7.     public void setUp() throws Exception {   
  8.         setUp("http://localhost:9060/""*firefox");                                        // Modify this line   
  9.     }   
  10.     public void testMasterLogin() throws Exception {   
  11.         selenium.open("/gm/login.jsf");   
  12.         selenium.type("j_username""tongweb");   
  13.         selenium.type("j_password""tongweb");   
  14.         selenium.click("j_security_check");   
  15.         selenium.waitForPageToLoad("30000");   
  16.         assertEquals("TongWeb管理控制台", selenium.getTitle());                    // Judging the testcase is pass or failed by add a assert.   
  17.     }   
  18. }  
package com.example.tests; import com.thoughtworks.selenium.*; import java.util.regex.Pattern; public class MasterLogin extends SeleneseTestCase { public void setUp() throws Exception { setUp("http://localhost:9060/", "*firefox"); // Modify this line } public void testMasterLogin() throws Exception { selenium.open("/gm/login.jsf"); selenium.type("j_username", "tongweb"); selenium.type("j_password", "tongweb"); selenium.click("j_security_check"); selenium.waitForPageToLoad("30000"); assertEquals("TongWeb管理控制台", selenium.getTitle()); // Judging the testcase is pass or failed by add a assert. } }

3.Selenium-RC安装使用

简介

      Selenium RC(Remote Control)是一个基于java编写的开源测试工具,允许使用多种语言编写自动化的WEB UI测试用例。这个工具提供一个Selenium Server可以启动,停止和控制绝大多数主流浏览器,这个服务器使用AJAX直接和浏览器进行交互,可以使用HTTP GET/POST请求向Selenium Server发送命令。

      Selenium-RC安装包包含两部分:Selenium-server、Selenium-client-driver(各语言版本分别对应一个 client-driver.jar),server为测试服务器,client-driver为测试用例的API(编写测试用例的使用用到)。




安装:

   1. 安装1.5及以上版本的JDK
   2. 官网下载最新版Selenium-RC组件至本地,直接解压便可使用

启动Server:
启动命令java -jar Selenium-server.jar 可以带参数启动,如java -jar selenium-server.jar -interactive为以交互模式启动,这里自己可以将启动操作制作成简单的.bat或.sh脚本,如bat脚本(此脚本与selenium- server.jar在同一级目录下):

Java代码 复制代码
  1.  @echo off   
  2. rem ---------------------------------------------------------------------------   
  3. rem   Start Selenium Server   
  4. rem   Add by pengyao 08/26/2010  
  5. rem ---------------------------------------------------------------------------   
  6.   
  7. java -jar selenium-server.jar  
@echo off rem --------------------------------------------------------------------------- rem Start Selenium Server rem Add by pengyao 08/26/2010 rem --------------------------------------------------------------------------- java -jar selenium-server.jar

开发运行测试用例:

这里采用java语言为例来进行说明:

   1. 解压Selenium-RC压缩包,取出selenium-java-client-driver.jar
   2. 打开Java IDE(Eclipse, NetBeans, IntelliJ, Netweaver, etc.)
   3. 新建一个project
   4. 将selenium-java-client-driver.jar导入此project的classpath
   5. 将Selenium-IDE录制好的html脚本转换成java文件,导入新建的project(可能需要稍作修改,如添加assert判断用例是否测试通过),或直接使用selenium-java-client API编写测试用例。本工具同时支持Junit和TestNg测试框架。
   6. 启动Selenium Server
   7. 在Java IDE 或命令行执行编写好的测试用例

4.Selenium-RC工作原理




(1).测试案例(Testcase)通过Client Lib的接口向Selenium Server发送Http请求,要求和Selenium Server建立连接。

(2).Selenium Server的Launcher启动浏览器,把Selenium Core加载入浏览器页面当中,并把浏览器的代理设置为Selenium Server的Http Proxy。

(3).测试案例通过Client Lib的接口向Selenium Server发送Http请求,Selenium Server对请求进行解析,然后通过Http Proxy发送JS命令通知Selenium Core执行操作浏览器的动作。

(4).Selenium Core接收到指令后,执行操作。

(5).浏览器收到新的页面请求信息(因为在(4)中,Selenium Core的操作可能引发新的页面请求),于是发送Http请求,请求新的Web页面。
由于Selenium Server在启动浏览器时做了手脚,所以Selenium Server会接收到所有由它启动的浏览器发送的请求。

(6).Selenium Server接收到浏览器的发送的Http请求后,自己重组Http请求,获取对应的Web页面。

(7).Selenium Server的Http Proxy把接收的Web页面返回给浏览器。
5.Selenium-RC优缺点

与Watij对比的优势:
编号 Selenium Watij
1 跨浏览器 仅IE
2 跨操作系统 仅Windows
3 支持多数主流编程语言C#,Java,PHP,Ruby,Prel,Groovy,Python等 仅java
4 提供Hudson插件,容易与Hudson整合 未提供Hudson插件
5 可以录制和回放脚本,并可以将录制好的脚本转换成各种主流编程语言 未提供此功能
6 API强大,文档全 ?
7 属于同类产品中主流,官方资料详细、拥有正规的中文论坛 较主流,资料不是特别多
8 发展迅速 发展缓慢,出现替代产品

缺点:

   1. 对弹出窗口、上传、下载功能测试不太方便,需要借助第三方工具包AutoIt3(但是在使用过程中没有遇见什么问题,可能这个问题是以前版本的问题,而且watij这方面也存在点问题)

6.Selenium-RC与Hudson整合

      Selenium提供了Hudson持续集成插件,可以与Hudson进行整合(这里如果确定采用此工具再具体研究怎么整合)。
7.Selenium-RC常用API

一. 文本框Text box

  1. 向文本框中填写信息

Java代码 复制代码
  1.   type(java.lang.String locator, java.lang.String value)  //eg.selenium.type("salutationText", "abc");  
  type(java.lang.String locator, java.lang.String value)  //eg.selenium.type("salutationText", "abc");

  2. 取出某个文本框中已经填写的信息

Java代码 复制代码
  1.   java.lang.String  getValue(java.lang.String locator)    
  2.     
  3.     //eg:selenium.getValue("xpath=//input@name='addProfileLastName'");  
  java.lang.String getValue(java.lang.String locator)    //eg:selenium.getValue("xpath=//input@name='addProfileLastName'");

  3. 判断某文本框是否可编辑


Java代码 复制代码
  1.   boolean isEditable(java.lang.String locator)  //eg.selenium.isEditable("xpath=//input@name='addProfileLastName'");  
  boolean isEditable(java.lang.String locator)  //eg.selenium.isEditable("xpath=//input@name='addProfileLastName'");

  二.下拉框 Drop down list

  1. 向下拉框中选值

Java代码 复制代码
  1.   select(java.lang.String selectLocator, java.lang.String optionLocator)  //eg.selenium.select("typeSelect", "label=Date");  
  select(java.lang.String selectLocator, java.lang.String optionLocator)  //eg.selenium.select("typeSelect", "label=Date");

  2. 取出某个下拉框中已经选择的值

Java代码 复制代码
  1.   java.lang.StringgetSelectedLabel(java.lang.String selectLocator)  //eg. selenium.getSelectedLabel("xpath=//SELECT@name='addSatution'")  
  java.lang.StringgetSelectedLabel(java.lang.String selectLocator)  //eg. selenium.getSelectedLabel("xpath=//SELECT@name='addSatution'")

  3. 取出某个下拉框中所有的选项

Java代码 复制代码
  1.   java.lang.String[]  getSelectOptions getSelectOptions getSelectOptions(java.lang.String selectLocato getSelectOptionsr)  //eg. selenium.getSelectOptions("//div@id='mysearch_tips'/select")  
  java.lang.String[] getSelectOptions getSelectOptions getSelectOptions(java.lang.String selectLocato getSelectOptionsr)  //eg. selenium.getSelectOptions("//div@id='mysearch_tips'/select")

  三.按钮或链接Button & Link

  单击

Java代码 复制代码
  1.   click(java.lang.String locator)  //eg. selenium.click("link=Administration");  //selenium.click("xpath=//input@checkfield='addIndicatorName' and @name='addBtn'");  
  click(java.lang.String locator)  //eg. selenium.click("link=Administration");  //selenium.click("xpath=//input@checkfield='addIndicatorName' and @name='addBtn'");

  四. 单选框或多选框 Radio Box & Check Box

  1. 选择

Java代码 复制代码
  1.   check(java.lang.String locator)  //eg. selenium.check("otherPhoneFlag");  
  check(java.lang.String locator)  //eg. selenium.check("otherPhoneFlag");

  1. 不选

Java代码 复制代码
  1.   uncheck(java.lang.String locator)   
  2.   //eg. selenium.uncheck("otherPhoneFlag");  
  uncheck(java.lang.String locator)   //eg. selenium.uncheck("otherPhoneFlag");

  2. 判断是否选择

Java代码 复制代码
  1.   booleanisChecked(java.lang.String locator)  //eg. selenium.isChecked("otherPhoneFlag");  
  booleanisChecked(java.lang.String locator)  //eg. selenium.isChecked("otherPhoneFlag");

  五.表格Table

  1. 取出表中某个单元格的值,下标从 0 开始

 
Java代码 复制代码
  1.  java.lang.String getTable(java.lang.String tableCellAddress)  //eg. selenium.getTable("//div@id='profiles-search'/div2/table.1.1");  
 java.lang.String getTable(java.lang.String tableCellAddress)  //eg. selenium.getTable("//div@id='profiles-search'/div2/table.1.1");

  六.其他 others

  1. 取某个元素的特定属性值

Java代码 复制代码
  1.   java.lang.String getAttribute(java.lang.String attributeLocator)  //eg. selenium.getAttribute("xpath=//img@name='picName'@style")  
  java.lang.String getAttribute(java.lang.String attributeLocator)  //eg. selenium.getAttribute("xpath=//img@name='picName'@style")

  2.取某元素的 text 值

Java代码 复制代码
  1.   java.lang.String getText(java.lang.String locator)  //eg. selenium.getText("link=Contacts")  
  java.lang.String getText(java.lang.String locator)  //eg. selenium.getText("link=Contacts")

  3. 取当前页面的 Title

Java代码 复制代码
  1.   java.lang.String getTitle()  //eg. selenium.getTitle()  
  java.lang.String getTitle()  //eg. selenium.getTitle()

  4. 判断页面是否有特定的元素

Java代码 复制代码
  1.   boolean  isElementPresent(java.lang.String locator)  //eg. booleanisElementPresent(java.lang.String locator)  
  boolean isElementPresent(java.lang.String locator)  //eg. booleanisElementPresent(java.lang.String locator)

  5. 判断页面是否有特定文字

Java代码 复制代码
  1.   boolean isTextPresent(java.lang.String pattern)  
  boolean isTextPresent(java.lang.String pattern)

  6. 判断某个元素是否 invisible,图片是空的 the "display" property to "none"或 CSS "visibility" property to "hidden"

Java代码 复制代码
  1.   boolean isVisible(java.lang.String locator)  //eg.selenium.isVisible("xpath=//img@name='picName'")  
  boolean isVisible(java.lang.String locator)  //eg.selenium.isVisible("xpath=//img@name='picName'")
  7. 模拟 Keyup 事件

Java代码 复制代码
  1.   keyUp(java.lang.String locator,java.lang.String keySequence)  //eg. selenium.keyUp("creditCardExpMonth", "1");  
  keyUp(java.lang.String locator,java.lang.String keySequence)  //eg. selenium.keyUp("creditCardExpMonth", "1");

  8. 打开一个 url,相对或绝对

Java代码 复制代码
  1.   open(java.lang.String url)  //eg.selenium.open("/login.aspx");  
  open(java.lang.String url)  //eg.selenium.open("/login.aspx");

  9. 刷新页面

 
Java代码 复制代码
  1.  refresh()  //eg.selenium.refresh();  
 refresh()  //eg.selenium.refresh();

  10. 控制每步操作间隔的时间,milliseconds

Java代码 复制代码
  1.   setSpeed(java.lang.String value)  //eg. selenium.setSpeed("3000");  
  setSpeed(java.lang.String value)  //eg. selenium.setSpeed("3000");

  11. 开始一个 Selenium session

Java代码 复制代码
  1.     start()  //eg. selenium.start();  
  start()  //eg. selenium.start();

  12. 结束测试

Java代码 复制代码
  1.   stop()  //eg. selenium.stop();  
  stop()  //eg. selenium.stop();

  13. 等待新页面加载

Java代码 复制代码
  1.   waitForPageToLoad(java.lang.String timeout)  //selenium.waitForPageToLoad("60000");  
  waitForPageToLoad(java.lang.String timeout)  //selenium.waitForPageToLoad("60000");

  14. 页面最大化

Java代码 复制代码
  1.   windowMaximize()  //eg.selenium.windowMaximize();  
  windowMaximize()  //eg.selenium.windowMaximize();

8.完整的一个例子

下面是一个完整的创建JDBC连接池和删除JDBC连接池的测试用例:

Java代码 复制代码
  1. package com.tongweb.selenium.test;   
  2.   
  3. import com.thoughtworks.selenium.SeleneseTestCase;   
  4.   
  5. /**  
  6.  * 集中管理工具中创建一个名为jdbcpool_test连接池,创建成功后进行删除操作,  
  7.  * 为了更好的展示界面是如何操作的,所以加入不少sleep语句。  
  8.  * @author pengyao  07/09/2010  
  9.  *  
  10.  */  
  11.   
  12. public class CreateAndDeleteJdbcConnectPoolTestCase extends SeleneseTestCase {   
  13.       
  14.     public void setUp() throws Exception {   
  15.         setUp("http://localhost:9060/""*firefox");   
  16.     }   
  17.   
  18.     public void testCreateAndDeleteJdbcConnectPool() throws Exception {   
  19.         selenium.windowMaximize();   
  20.         selenium.open("/gm/login.jsf");   
  21.         selenium.type("j_username""tongweb");   
  22.         selenium.type("j_password""tongweb");   
  23.         selenium.click("j_security_check");   
  24.         selenium.waitForPageToLoad("30000");   
  25.         selenium.selectFrame("mainFrame");   
  26.         selenium.click("b1");   
  27.   
  28.         // jdbcpool_test JDBC连接池radio在页面的xpath路径   
  29.         String jdbcpool_test = "//tr[td/a='jdbcpool_test']/td[1]/input";   
  30.         // 判断如果jdbcpool_test JDBC连接池已存在,则先进行删除操作   
  31.         boolean isExist = selenium.isElementPresent(jdbcpool_test);   
  32.         if (isExist) {   
  33.             selenium.click("//tr[td/a='jdbcpool_test']/td[1]/input");   
  34.             Thread.sleep(3000);   
  35.             selenium.click("TongWebIndex:j_id_id273");   
  36.             Thread.sleep(3000);   
  37.             selenium.waitForPageToLoad("30000");   
  38.   
  39.         }   
  40.         // 填写必要参数   
  41.         selenium.click("TongWebIndex:j_id_id271");   
  42.         selenium.waitForPageToLoad("30000");   
  43.         selenium.type("createConnectPool:ConnPoolName""jdbcpool_test");   
  44.         selenium.select("createConnectPool:resType",   
  45.                 "label=javax.sql.DataSource");   
  46.         selenium.select("createConnectPool:dataSourceMap",   
  47.                 "label=MySQL Connector/J Type 4 Driver for MySQL");   
  48.         selenium.type("createConnectPool:ConnPoolDesc""aaa");   
  49.         selenium.addSelection("createConnectPool:j_id_id137",   
  50.                 "label=192.168.11.24:7200");   
  51.         selenium.click("createConnectPool:j_id_id148");   
  52.         selenium.waitForPageToLoad("30000");   
  53.         selenium.type("createConnectPoolProps:username""root");   
  54.         selenium.type("createConnectPoolProps:connURL",   
  55.                 "jdbc:mysql://192.168.11.24:3306/test?user=root");   
  56.         selenium.click("add");   
  57.         selenium.type("propName_0""ddd");   
  58.         selenium.type("propValue_0""ddd");   
  59.         selenium.click("createConnectPoolProps:j_id_id372");   
  60.         selenium.waitForPageToLoad("30000");   
  61.         Thread.sleep(5000);   
  62.   
  63.         // 判断是否创建成功   
  64.         assertTrue(selenium.isElementPresent(jdbcpool_test));   
  65.   
  66.         selenium.click("//tr[td/a='jdbcpool_test']/td[1]/input");   
  67.         Thread.sleep(3000);   
  68.         selenium.click("TongWebIndex:j_id_id273");   
  69.         selenium.waitForPageToLoad("30000");   
  70.   
  71.         // 判断是否删除成功   
  72.         assertFalse(selenium.isElementPresent(jdbcpool_test));   
  73.     }   
  74. }   
  75.    
package com.tongweb.selenium.test; import com.thoughtworks.selenium.SeleneseTestCase; /** * 集中管理工具中创建一个名为jdbcpool_test连接池,创建成功后进行删除操作, * 为了更好的展示界面是如何操作的,所以加入不少sleep语句。 * @author pengyao 07/09/2010 * */ public class CreateAndDeleteJdbcConnectPoolTestCase extends SeleneseTestCase { public void setUp() throws Exception { setUp("http://localhost:9060/", "*firefox"); } public void testCreateAndDeleteJdbcConnectPool() throws Exception { selenium.windowMaximize(); selenium.open("/gm/login.jsf"); selenium.type("j_username", "tongweb"); selenium.type("j_password", "tongweb"); selenium.click("j_security_check"); selenium.waitForPageToLoad("30000"); selenium.selectFrame("mainFrame"); selenium.click("b1"); // jdbcpool_test JDBC连接池radio在页面的xpath路径 String jdbcpool_test = "//tr[td/a='jdbcpool_test']/td[1]/input"; // 判断如果jdbcpool_test JDBC连接池已存在,则先进行删除操作 boolean isExist = selenium.isElementPresent(jdbcpool_test); if (isExist) { selenium.click("//tr[td/a='jdbcpool_test']/td[1]/input"); Thread.sleep(3000); selenium.click("TongWebIndex:j_id_id273"); Thread.sleep(3000); selenium.waitForPageToLoad("30000"); } // 填写必要参数 selenium.click("TongWebIndex:j_id_id271"); selenium.waitForPageToLoad("30000"); selenium.type("createConnectPool:ConnPoolName", "jdbcpool_test"); selenium.select("createConnectPool:resType", "label=javax.sql.DataSource"); selenium.select("createConnectPool:dataSourceMap", "label=MySQL Connector/J Type 4 Driver for MySQL"); selenium.type("createConnectPool:ConnPoolDesc", "aaa"); selenium.addSelection("createConnectPool:j_id_id137", "label=192.168.11.24:7200"); selenium.click("createConnectPool:j_id_id148"); selenium.waitForPageToLoad("30000"); selenium.type("createConnectPoolProps:username", "root"); selenium.type("createConnectPoolProps:connURL", "jdbc:mysql://192.168.11.24:3306/test?user=root"); selenium.click("add"); selenium.type("propName_0", "ddd"); selenium.type("propValue_0", "ddd"); selenium.click("createConnectPoolProps:j_id_id372"); selenium.waitForPageToLoad("30000"); Thread.sleep(5000); // 判断是否创建成功 assertTrue(selenium.isElementPresent(jdbcpool_test)); selenium.click("//tr[td/a='jdbcpool_test']/td[1]/input"); Thread.sleep(3000); selenium.click("TongWebIndex:j_id_id273"); selenium.waitForPageToLoad("30000"); // 判断是否删除成功 assertFalse(selenium.isElementPresent(jdbcpool_test)); } }

9.Selenium常见问题

1.需要把浏览器的启动程序添加至PATH环境变量中,否则会抛出异常。提示不能打开浏览器;

2.如果将浏览器的启动程序添加至PATH环境变量中,还是不能打开浏览器,可能是Selenium版本不支持此浏览器版本,支持信息可以通过查看 Selenium-RC的selenium-server.jar中install.rdf 文件看此Selenium都支持那些版本浏览器;

3. 抛Element not found异常时, 一般有两个原因:一个是页面还没加载完,需要添加一条Thread.sleep()语句;一个可能是查找方式有误,比如xpath或id不正确,或查找顺序不正确;

4.selectFrames进入某个frame后,重新选择其它frame时,有时需要退出本frame,如selenium.selectFrame("relative=up");

5.使用Selenium IDE进行脚本录制时,在TWNS管理控制台对功能树的操作不能录制下来,需要手动添加这部分的脚本 ;

6.有时元素找到了,但是挂在那(比如说一个submit按钮,附带了onclick="return xxx"触发事件,把onclick去掉就好了,这个还没找到好的解决方法)

358°/3582 人阅读/0 条评论 发表评论

登录 后发表评论