GVKun编程网logo

selenium+ Webrat +selenium指南(selenium+webdriver)

25

在本文中,我们将给您介绍关于selenium+Webrat+selenium指南的详细内容,并且为您解答selenium+webdriver的相关问题,此外,我们还将为您提供关于c#–是否可以在不安装

在本文中,我们将给您介绍关于selenium+ Webrat +selenium指南的详细内容,并且为您解答selenium+webdriver的相关问题,此外,我们还将为您提供关于c# – 是否可以在不安装Selenium Server的情况下使用ISelenium / DefaultSelenium?、org.openqa.selenium.WebDriverBackedSelenium的实例源码、Robot Framework + Selenium2Library 环境下,结合 Selenium Grid 实施分布式自动化测试、selenium IDE(五)selenium 命令之定位页面元素的知识。

本文目录一览:

selenium+ Webrat +selenium指南(selenium+webdriver)

selenium+ Webrat +selenium指南(selenium+webdriver)

我已经使用Cucumber和Webrat已有一段时间了。现在,我需要开始编写涉及AJAX交互的行为,因此我正在考虑将Selenium适配器用于Webrat。谁能指出安装和配置selenium
+ webrat + cucumber的简便且更新的分步指南?我希望能够将javascript方案与非javascript方案混合使用。

答案1

小编典典

我在项目上将Selenium与rspec结合使用,并从Selenium IDE的自定义格式化程序生成代码。

硒有很多,但是我使用Selenium-
RC成功http://seleniumhq.org/download/,所以请下载到您的PC。

这是我的步骤:

  1. 解压缩并运行> java -jar selenium-server.jar
  2. 打开selenium-client-ruby,阅读文档,跟随它,您将获得成功!
  3. gem install rspec,rspec-rails版本1.2.6(不是,您需要注释selenium-client源代码的版本限制)
  4. gem install硒客户端
  5. 打开Selenium-IDE(当然是Firefox),打开选项->选项->格式
  6. 单击添加,然后将此代码粘贴到http://www.techdarkside.com/rspec_export.txt中

现在,您只需要为我导出规范到您的规范文件夹,我就使用spec / features / xxxx_spec.rb参见下面的代码。

在这里可以找到非常相似的方法

对于webrat + cucumber,最新的Rspec手册将为您提供所需的一切。(他们还没有硒+黄瓜章节完成)

 require ''rubygems''gem "rspec", "=1.2.6"gem "selenium-client", ">=1.2.15"require "selenium/client"require "selenium/rspec/spec_helper"describe "Google Search" do    attr_reader :selenium_driver    alias :page :selenium_driver  before(:all) do      @selenium_driver = Selenium::Client::Driver.new \          :host => "localhost",          :port => 4444,          :browser => "*firefox",          :url => "http://www.google.com",          :timeout_in_second => 60  end  before(:each) do    selenium_driver.start_new_browser_session  end  # The system capture need to happen BEFORE closing the Selenium session  append_after(:each) do    @selenium_driver.close_current_browser_session  end  it "can find Selenium" do    page.open "/"    page.title.should eql("Google")    page.type "q", "Selenium seleniumhq"    page.click "btnG", :wait_for => :page    page.value("q").should eql("Selenium seleniumhq")    page.text?("seleniumhq.org").should be_true    page.title.should eql("Selenium seleniumhq - Google Search")    page.text?("seleniumhq.org").should be_true            page.element?("link=Cached").should be_true  endend

c# – 是否可以在不安装Selenium Server的情况下使用ISelenium / DefaultSelenium?

c# – 是否可以在不安装Selenium Server的情况下使用ISelenium / DefaultSelenium?

我之前使用IWebDriver控制IE进行测试.但是IWebDriver和IWebElement支持的方法非常有限.我发现属于Selenium命名空间的ISelenium / DefaultSelenium非常有用.如何在不安装Selenium Server的情况下使用它们来控制IE?

这是DefaultSelenium的构造函数:

ISelenium sele = new DefaultSelenium(**serveraddr**,**serverport**,browser,url2test);
sele.Start();
sele.open();
...

似乎我必须在创建ISelenium对象之前安装Selenium Server.

我的情况是,我正在尝试使用C#Selenium构建一个.exe应用程序,它可以在不同的PC上运行,并且不可能在所有PC上安装Selenium Server(你永远不知道哪个是下一个运行应用程序).

有没有人知道如何在不安装服务器的情况下使用ISelenium / DefaultSelenium?
谢谢!

解决方法

在不使用RC Server的情况下,Java中有一些解决方案:

1)对于selenium浏览器启动:

DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setbrowserName("safari");
CommandExecutor executor = new SeleneseCommandExecutor(new URL("http://localhost:4444/"),new URL("http://www.google.com/"),capabilities);
WebDriver driver = new RemoteWebDriver(executor,capabilities);

2)对于selenium命令:

// You may use any WebDriver implementation. Firefox is used here as an example
WebDriver driver = new FirefoxDriver();

// A "base url",used by selenium to resolve relative URLs
 String baseUrl = "http://www.google.com";

// Create the Selenium implementation
Selenium selenium = new WebDriverBackedSelenium(driver,baseUrl);

// Perform actions with selenium
selenium.open("http://www.google.com");
selenium.type("name=q","cheese");
selenium.click("name=btnG");

// Get the underlying WebDriver implementation back. This will refer to the
// same WebDriver instance as the "driver" variable above.
WebDriver driverInstance = ((WebDriverBackedSelenium) selenium).getWrappedDriver();

//Finally,close the browser. Call stop on the WebDriverBackedSelenium instance
//instead of calling driver.quit(). Otherwise,the JVM will continue running after
//the browser has been closed.
selenium.stop();

描述于此:http://seleniumhq.org/docs/03_webdriver.html

谷歌在C#中有类似的东西.没有其他方法可以实现这一目标.

org.openqa.selenium.WebDriverBackedSelenium的实例源码

org.openqa.selenium.WebDriverBackedSelenium的实例源码

项目:OpenNMS    文件:OpenNMSSeleniumTestCase.java   
@Before
public void setUp() throws Exception {
    MockLogAppender.setupLogging(true,"DEBUG");

    // Google Chrome
    // System.setProperty("webdriver.chrome.driver","/Users/ranger/Downloads/chromedriver");
    // WebDriver driver = new ChromeDriver();

    // Selenium Remote Server
    // DesiredCapabilities capability = DesiredCapabilities.firefox();
    // WebDriver driver = new RemoteWebDriver(new URL("http://localhost:4444/wd/hub"),capability);

    // Firefox
    WebDriver driver = new FirefoxDriver();

    String baseUrl = "http://localhost:8980/";
    selenium = new WebDriverBackedSelenium(driver,baseUrl);
    selenium.open("/opennms/login.jsp");
    selenium.type("name=j_username","admin");
    selenium.type("name=j_password","admin");
    selenium.click("name=Login");
    waitForPagetoLoad();
}
项目:Prospero    文件:WebDriverBackedSeleniumDriver.java   
protected WebDriverBackedSeleniumDriver(WebDriver wd,String url) {
super();
setSiteUrl(url);
Selenium wdbs = new WebDriverBackedSelenium(wd,url);
setSelenium(wdbs);
startSelenium();
   }
项目:crawljax    文件:OverviewIntegrationTest.java   
@BeforeClass
public static void setup() throws Exception {
    LOG.debug("Starting Jetty");
    server = new Server(0);

    String url = setupJetty();
    LOG.info("Jetty started on {}",url);
    driver = new FirefoxDriver();
    LOG.debug("Starting selenium");
    selenium = new WebDriverBackedSelenium(driver,url);

    driver.manage().timeouts().implicitlyWait(30,TimeUnit.SECONDS);
}
项目:Mahesh.tutorials    文件:WrapperFunctions.java   
/**
 * @param driver
 * @param locator
 */

public void hoverMouSEOn(WebDriver driver,String locator) {
    WebDriverBackedSelenium selenium = new WebDriverBackedSelenium(driver,driver.getcurrenturl());
    selenium.mouSEOver(locator);
}
项目:selenium-yatspec-petclinic    文件:OwnerPage.java   
public OwnerPage(WebDriverBackedSelenium selenium) {
    super("Owners",selenium,HomePage.PAGE_TITLE);
    if (!selenium.getHtmlSource().contains("Owner information")) {
        String msg = format("Owner information page has not been loaded from [%s]",selenium.getLocation());
        throw new NotCorrectPageException(msg);
    }
}
项目:selenium-yatspec-petclinic    文件:AddOwnerPage.java   
public AddOwnerPage(WebDriverBackedSelenium selenium) {
    super("Add Owner",HomePage.PAGE_TITLE);
    if (!selenium.getHtmlSource().contains(" New  Owner")) {
        String msg = format("Add Owner page has not been loaded from [%s]",selenium.getLocation());
        throw new NotCorrectPageException(msg);
    }
}
项目:selenium-yatspec-petclinic    文件:FindOwnersPage.java   
public FindOwnersPage(WebDriverBackedSelenium selenium) {
    super("Find Owners",HomePage.PAGE_TITLE);
    if (!selenium.getHtmlSource().contains("Find Owners")) {
        String msg = format("Find Owners page has not been loaded from [%s]",selenium.getLocation());
        throw new NotCorrectPageException(msg);
    }
}
项目:selenium-yatspec-petclinic    文件:HomePage.java   
public HomePage(WebDriverBackedSelenium selenium) {
    super("Home",PAGE_TITLE);
    if (!selenium.getHtmlSource().contains("Welcome")) {
        String msg = format("Home page has not been loaded from [%s]",selenium.getLocation());
        throw new NotCorrectPageException(msg);
    }
}
项目:selenium-yatspec-petclinic    文件:BasePage.java   
public BasePage(String internalPageName,WebDriverBackedSelenium selenium,String expectedPageText) {
    this.internalPageName = internalPageName;
    this.selenium = selenium;
    String html = getHtml();
    if (!html.contains(expectedPageText)) {
        String msg = format("Page body (%s) does not contain expected text (%s),current page is: %s",html,expectedPageText,selenium.getLocation());
        throw new NotCorrectPageException(msg);
    }
}
项目:EarthWorm    文件:browserEmulator.java   
public browserEmulator() {
    setupbrowserCoreType(GlobalSettings.browserCoreType);
    browser = new WebDriverBackedSelenium(browserCore,"https://github.com/");
    javaScriptExecutor = (JavascriptExecutor) browserCore;
    logger.info("Started browserEmulator");
}
项目:EarthWorm    文件:browserEmulator.java   
/**
 * 获取 WebDriverBackedSelenium 实例
 * @return
 */
public WebDriverBackedSelenium getbrowser() {
    return browser;
}

Robot Framework + Selenium2Library 环境下,结合 Selenium Grid 实施分布式自动化测试

Robot Framework + Selenium2Library 环境下,结合 Selenium Grid 实施分布式自动化测试

         最近一段时间,公司在推行自动化测试流程,本人有幸参与了自定义通用控件的关键字封装和脚本辅助编写、数据驱动管理、测试用例执行管理等一系列工具软件的研发工作,积累了一些经验,在此与大家做一下分享,也算是做一个总结吧,希望能给大家带来启发和帮助。由于业界没有成熟的解决方案可供参考,本人在研究过程中也是摸着石头过河,纰漏之处在所难免,如果大家有更好的方案,敬请不吝赐教。

 

分布式并行执行用例需求背景

        公司的产品属于 web app,采用的是 Robot Framework + Selenium2Library 作为自动化测试的框架。脚本开发完毕,在推广试用的过程中,测试人员反馈了一个问题:当 case 数量很多的时候,需要执行很长的时间才能跑完,这往往无法跟上产品发布迭代的节奏。他们的要求是:100 个 case 要求在一个小时之内跑完 (平均一个 case 需要 3 到 5 分钟)。经过对比和研究,最终决定利用 Selenium Grid 来将这些 case 分散到多台机器去执行,通过分布式并行执行的方式,压缩执行时间。

        关于 Selenium Grid 的介绍、运行原理、安装部署等细节,请参考 http://blog.csdn.net/five3/article/details/9428655,在此不作详述。

 

分布式并行执行用例管理工具一览

        为了更好的贴合公司实际需求,我开发了一个 winform 应用程序来管理 case 的执行过程。主要功能包括:

        1. 支持本机执行和分布式并行执行这两种执行方式

        2. 由于环境和框架本身的不稳定性,需要在脚本出错的情况下 (包括 case fail 掉了或者是 robot framework 框架出错),能自动对出错的 case 做一定的重试,以此消除环境的不稳定因素对执行过程的影响。

        3. 支持有条件的并行 (有条件并行的概念将在后面介绍)。

        工具界面如下 (左侧是 case 选择界面,右侧是选项面板和执行结果信息):

       

       

Robot Framework 与 Selenium Grid 之间的桥梁

        Selenium Grid 安装好之后,是一个独立的系统,与外界没有任何联系,它不会自动获取 case、自动分发请求。所以,要利用 Selenium Grid,首先要研究如何把 case 执行请求发送给 Grid。

        网上有不少介绍 Selenium Grid 的文章,多以 webdriver 的 API 作为与 Selenium Grid 交互的途径,典型代码如下:

DesiredCapabilities dc = DesiredCapabilities.firefox();
WebDriver dr = new RemoteWebDriver(new URL("http://192.168.40.67:5555/wd/hub"),dc);
dr.get("http://www.baidu.com");

        但是 Robot Framework 如何与 Selenium Grid 进行交互呢?我们知道,Robot Framework 只是一个自动化测试框架而已,它之所以能够测试各种类型的应用程序,是因为它可以挂接不同的库,比如,挂接 Selenium2Library,就可以测试 web app,最终执行测试的动作还是由相应的库来完成的。

        Selenium2Library 对 selenium 类库做了一下包装,形成了相应的 python 类,与 selenium 相关的关键字就是调用这些类的方法,比如:关键字 “open browser” 就是调用的_BrowserManagementKeywords 这个类的 open_browser 方法 (python 文件路径为 C:\Python27\Lib\site-packages\Selenium2Library\keywords\_browsermanagement.py,安装方式不同,路径会略有不同)。

        研究这个方法的代码可以知道,参数 remote_url 的作用与上面 RemoteWebDriver 类构造方法的第一个参数的作用是类似的。于是,我们可以考虑在这个参数上做文章。那么,我们是否需要修改所有 case 的脚本,如下图所示加上这个参数呢?

        显然,这种方式不好。两个原因:1. 需要大量的修改现有的脚本;2. 参数是写死的,无法与工具选项设置关联起来。

        所以,在不修改脚本的情况下,要同时支持在本地和分布式执行用例,最直接的方法就是修改_BrowserManagementKeywords 类的 open_browser 方法,因为不管是哪种执行方式,这个方法都会被调用。

        另外,工具选项面板上的执行方式选项如何通知给这个方法呢?我的办法是通过一个全局桥梁文件来作为彼此通信的纽带,工具依据选项设置生成或者删除桥梁文件;open_browser 方法判断文件是否存在并读取文件内容作为 remote_url 参数的值。

        工具选项设置代码片段:

//Hub URL存放文件
private const string SeleniumGridHubUrlFilePath = "c:\\SeleniumGridHubUrl.txt";
//生成、删除remote url参数文件            
if (this.radioButton1.Checked)
{
    File.Delete(SeleniumGridHubUrlFilePath);
}
else
{
    File.WriteAllText(SeleniumGridHubUrlFilePath,string.Format("http://{0}:4444/wd/hub",this.textBox3.Text.Trim()));
}

        py 文件方法修改:

 

Robot Framework 命令行介绍

        打通了 Robot Framework 与 Selenium Grid 之间的联系之后,我们开始研究如何通过工具执行 case。

        在脚本开发调试过程中,一般用的 RIDE 集成环境,但是如果用工具来管理执行过程的话,就无法再使用 RIDE 了,只能想别的办法。如果仔细观察过 RIDE 的一些窗口输出信息的话,一定能注意到它会把本次执行对应的 DOS command 打印出来,如下图所示:

         其实,RIDE 就是调用这个命令行来执行用例的,所以我们也可以通过调用命令行的方式来执行用例。由于工具会涉及到执行用例、错误用例重试、合并报告这三种功能,所以这里就简单介绍一下这三个命令。更多命令,可以通过在 dos 命令行里面输入 pybot --help 查询。

       

        1. 执行用例

        --test : 指定要执行的 case 名称 (全路径)       --outputdir : log 存放路径    --argumentfile : 选项文件路径      参数 1 : 要执行的 suite 路径

        示例:

 

        2. 重试用例

        -R : 表示要重试错误用例    -d : 本次执行 log 存放路径    参数一:需要执行重试的 output.xml 文件路径    参数二 : suite 路径

        示例:

pybot -R D:\logs\2014-09-05-18-40-42\remote_1\tag__batch_0\output.xml -d D:\logs\2014-09-05-18-40-42\remote_2\tag__batch_0 D:\自动化测试111\成本系统

 

        3. 合并报告 (使用 rebot 指令,详细说明可以通过 rebot  --help 查看)

        -N :  重命名报告    -d :产生的新 log 的存放路径      参数一 : 需要合并的 log 路径 (支持通配符)

        示例:

rebot -N 第1次执行 -d D:\logs\2014-09-05-18-40-42\1 D:\logs\2014-09-05-18-40-42\remote_1\*\output.xml

 

        工具就是通过调用上述三个命令并辅以一定的流程控制逻辑来完成执行、重试、合并报告的功能。

        代码片段:首先生成一个批处理文件,然后启动一个 DOS 命令行窗口执行这个 bat 文件

//生成参数文件
string argFilePath = @"c:\RFSCommandLine\" + batchTime + "_argfile.txt";
string argFileContent = "--outputdir\r\n" + Path.Combine(logFolder, "1") + "\r\n" + BuildTestCaseCommandOption(selectedCases);
File.WriteAllText(argFilePath, argFileContent, Encoding.GetEncoding("utf-8"));

//生成批处理文件
batchFilePath = @"c:\RFSCommandLine\" + batchTime + "_1.bat";
content = string.Format(@"pybot.bat --argumentfile {0} {1}", argFilePath, currentProjectPath);
File.WriteAllText(batchFilePath, content, Encoding.GetEncoding("gb2312"));
//调用批处理文件
try
{
    Process p = new Process();
    p.StartInfo.FileName = batchFilePath;
    p.Start();
    p.WaitForExit();
}

 

工具设计思路分析

        一。基本概念介绍

        1. hub 分发请求的粒度

        刚开始研究 Selenium Grid 的时候,以为只要把所有选中的 case 放到一个批处理文件里面,然后运行该批处理,这样就可以把执行请求发送给 hub,hub 就会自动分发请求到各个空闲节点。但事实证明,不是这样的,hub 只会随机选择一个空闲节点,然后一根筋的把所有的 case 都分发到该节点执行,而不是分发给所有空闲的节点。这说明 hub 分发请求的粒度是批处理 DOS 命令行为单位的,而不是单个的 case,一个 DOS 命令行里的所有 case 始终是在同一个节点上执行,不会被打散。为了能多节点并行执行,我们需要人为的将这些 case 拆成一批一批的,也就是下面要介绍的请求批次的概念。

        2. 请求批次

        所谓 “请求批次”,指的是按照某种算法逻辑,将需要执行的 case 列表进行拆分,形成批次。举个例子,我有 100 条 case,如果设定每个批次包含 10 个 case,那么我们可以将这 100 个 case 拆分成 10 个批次。如果我同时将这 10 个批次发送给 hub,那么 hub 此时就会寻找所有空闲的节点,并将这些批次调度分发给这些节点执行,这样就可以达到并行的目的了。我这里是采用多线程技术完成这个任务,一个线程启动一个批处理文件,一个批处理文件中包含着一个批次的 case,三者之间是一一对应的关系。示意图如下:

 

代码片段:

for (int i = 0; i < splittedCaseList.Count; i++)
{
    string argFilePath = @"c:\RFSCommandLine\" + batchTime + "_argfile_tag_" + tag + "_" + i.ToString() + ".txt";
    string argFileContent = "--outputdir\r\n" + Path.Combine(Path.Combine(logFolder, "remote_1"), "tag_" + tag + "_batch_" + i.ToString()) + "\r\n" + BuildTestCaseCommandOption(splittedCaseList[i]);
    File.WriteAllText(argFilePath, argFileContent, Encoding.GetEncoding("utf-8"));

    batchFilePath = @"c:\RFSCommandLine\" + batchTime + "_1_tag_" + tag + "_" + i.ToString() + ".bat";
    content = string.Format(@"pybot.bat --argumentfile {0} {1}", argFilePath, currentProjectPath);

    File.WriteAllText(batchFilePath, content, Encoding.GetEncoding("gb2312"));

    Thread thread = new Thread(new ParameterizedThreadStart(RunRemoteCommand));
    threads.Add(thread);
    thread.Start(batchFilePath);
}

 

        3. 串行与并行

        “并行” 指的是多个批次的 case 可以分散到不同的节点同时执行;“串行” 指的是有些流程必须按顺序执行,比如:只有完成了第一次执行的所有批次之后,才可以进入第一次重试环节,第一次重试结束了,才可以开始第二次重试,所有重试结束之后,才可以开始合并报告。那么启动了那么多的线程,我们如何管理好它们的执行顺序呢?这里可以利用线程同步机制,在串行流程中,适当地做一下等待。代码片段:

//阻塞调用线程,等待所有并行线程都结束,才开始后续串行操作
foreach
(Thread thread in threads) { thread.Join(); }

 

        4. 全局资源与并行干扰 (有条件并行)

        " 全局资源 “指的是各个模块功能共用的一些配置、选项、或者数据库中公共的表之类的一些全局型的资源。全局资源具有排他性,比如:不能一个 case 把某个选项开关打开,而另外一个 case 同时又把这个开关关掉。如果这样的话,这两个 case 之间互相造成干扰,会导致 case 执行出错,或者测试结果不准确。所以说,并行并不是绝对的并行,而是有条件的,我们需要识别出这种隐藏在业务逻辑中的排斥关系。

        5. tag 分组

         目前,我是采用按 tag 分组的办法解决有条件并行的问题。我们可以在 case 上打上相关的特性 tag,先按照 tag 进行分组,每个组内再分批次。这样,tag 组内可以并行执行,tag 组与组之间必须串行执行。

 

 

        二。整体流程示意图

       

 

        三。工具开发中碰到的问题、优化、展望

        问题 1: 合并 log 时,rebot 命令不会自动把相关的出错截图拷贝到目标路径

        解决办法:合并之前,先修改一下每个批次里面的 output.xml 文件,对截图路径做一个修正,保持正确的相对路径即可。

        log 存放目录结构如下:

 

        代码片段:

//截图文件名关键字
string eleniumScreenshotKeyword = "selenium-screenshot-";
//读output.xml文件
string outputContent = File.ReadAllText(Path.Combine(remotePath, "output.xml"), Encoding.UTF8);
//修正截图路径为相当路径
outputContent = outputContent.Replace(eleniumScreenshotKeyword, string.Format("../remote_{0}/tag_{1}_batch_{2}/", i,tag, j) + eleniumScreenshotKeyword);
//保存output.xml文件
File.WriteAllText(Path.Combine(remotePath, "output.xml"), outputContent, Encoding.UTF8);

 

        问题 2: 批次同时执行 suite setup 会互相干扰

        我们有时需要在 suite 执行时先做一个初始化的动作,比如还原数据库快照,这可以通过设置 suite 的 suite setup 完成。问题是,当我们把 case 列表拆成多个批次并行执行时,每个批次都会执行一遍 suite setup,这同样存在并行干扰的问题。比如:批次 A 刚还原了数据库,正在跑 case,突然批次 B 又把数据库还原了,那么这两个批次之间就互相干扰了。

        解决办法:将 suite setup 的事情挪到工具里面来做,工具可以控制在适当的时机执行 suite setup,比如:第一次执行完毕,还原数据库,第一次重试,再还原数据库,第二次重试,再还原数据库...... 如此穿插执行。假设我有一个叫 “还原数据库” 的关键字,如何在工具里面调它呢?工具只会调 case,不会调关键字啊。我们知道,Robot Framework 的 case 和关键字资源文件其实都是一些普通的文本文件,是可以直接编辑的。于是想了一个变通的办法:修改某个 case 的内容,在最后追加一个 case,随便起个名字,就叫 “RestoreDB” 吧,这个 case 就调用 “还原数据库” 关键字。这样,就可以在工具中执行 RestoreDB 这个 case 做数据库还原了。

代码片段:

string restoreDBCaseStatement = "\r\n\r\nRestoreDB\r\n    数据库还原";
string fileContent = File.ReadAllText(caseFilePath);
//往case文件中增加RestoreDB
File.WriteAllText(caseFilePath, fileContent + restoreDBCaseStatement);

 

        问题 3: 执行环境不稳定、挂死

        在实际执行 case 的过程中,经常会出现一些莫名其妙的问题,比如:

        1. 跑着跑着 IEDriverServer.exe 这个进程不起作用了,僵死了

        2. 模态对话框很讨厌,特别是无法预知的模态框,如果不调用 confirm action 把它消掉的话,即使你在 test teardown 里面调 close all browsers,也是关不掉 IE 窗口的,这极有可能会导致 case 结束了,但 IE 进程和 IEDriverServer.exe 进程都还在的情形。

        不管怎么样,总是会出现 case 结束了,但 IEDriverServer.exe 进程还在的情况。对于本地执行方式来说,一旦有两个 IEDriverServer.exe 进程同时存在的话,那么执行环境就很不稳定了,什么奇怪的事情都可能发生;而对于 selenium grid 环境来说,如果一个 case 结束了,但 IEDriverServer.exe 进程还活着的话,会被 hub 认为该节点处于繁忙状态,hub 就不会给它分发下一个 case,那么当前批次一直被阻塞,其他批次也要等待这个批次 (线程同步),进而整个执行流程都会被阻塞,后果相当严重。

        如果是在本地执行的话,我可以在 case setup 里面调用 OperationSystem.Run 关键字去杀 IEDriverServer.exe 进程和 IE 进程;但是,如果是利用 selenium grid 分布式执行的话,这种操作系统级别的关键字,是无法通过 hub 转发到节点机器上执行的,因为 hub 只会转发 webdriver 支持的指令,其他指令都是在本地执行的。

        所有,必须要想办法保证每个 case 执行完毕后,IEDriverServer.exe 进程和 IE 进程都必须被清理掉,否则整个 Selenium Grid 体系就玩不转了,这点很重要。

        解决办法:我也没想到一个比较优雅的办法来解决 Selenium Grid 稳定性的问题,用的一个比较偏门的办法:

        1. 开发一个 WCF 服务部署到节点机器,它暴露的 URL 为:http://localhost:8732/gridservice/action/killprocess,其作用就是杀 IE 进程和 IEDriverServer 进程。

        2. 定义一个关键字,叫 “安全退出 case”,内容如下:

        3. 在 case 的 teardown 里面调用 “安全退出 case” 关键字

        这样做,为什么能达到目的呢?

        1. 首先调用 “close all browsers” 是为了杀 IEDriverServer 进程的 (但是有可能 IE 进程杀不掉,不过没关系),保证 hub 会开一个新的 session 执行后续的那个”open browser“命令。

        2. ”open browser“是 selenium 库支持的命令,所有是可以分发到 hub 的。

        3. 不管请求分发到哪个节点,localhost 都是指的是节点本机,所以调的是节点本机的服务,当然杀的也是节点自己的进程。

        4. 调用 “open browser” 访问 WCF 服务的 URL,类似于自杀式袭击。因为这个调用会报错,但是可以不用管,所有用 “Run Keyword And Ignore Error” 关键字保护起来。袭击完毕,各种残余都被清理的干干净净 (包括 IE 进程和 IEDriverServer 进程)。

        这个方案经过测试之后,发现有一个问题:正常情况下,IEDriverServer.exe 进程是在 webdriver 调用 quit 方法之后自动退出的,hub 与节点之间也是正常的交换信息;而采用自杀式袭击,来的比较突然,hub 根本不知道节点发生什么事情,好像变的有点无所适从了,不停的试图与节点建立联系 (但是节点又不会正确的通知自己的信息给 hub,因为它的进程是非正常终止),直到超时时间到了,才重新和节点建立一个新的 session,然后开始后续的执行。hub 的默认超时时间是 300 秒,要等的时间有点久,那么只好把这个时间设短一点吧,希望它早点超时,早点建立新 session。可以在启动 hub 的时候,通过 -timeout 选项设置超时时间。

java -jar selenium-server-standalone-2.39.0.jar -role hub -timeout 20

        经过上述优化之后,实际跑下来效果还可以,后续还要经过大规模的实际运行来考察这个方案是否成熟稳定。

        对于工具的后续规划,有两点考虑:

        1. 开发一个 grid 的集中管理程序,可以在一台机器上统一管理 hub、各个节点,包括 hub 的启动、关闭、节点与 hub 的连接及断开,这样就不用远程登录到每台机器去操作了。

        2. 开发一个调度程序,用于管理整个公司的测试时间安排,希望可以协调好优先级,均衡的利用 grid,不致于一会儿扎堆的使用 grid,一会儿又长时间的让 grid 空闲。

 

selenium IDE(五)selenium 命令之定位页面元素

selenium IDE(五)selenium 命令之定位页面元素

定位页面元素

对于很多selenium命令,target域是必须的。Target在web页面范围内识别UI元素,它使用locatorType=location的格式。在很多情况下,locatorType可以省略,下面举例方式来描述各种类型的locatorType.

假如,有如下一段HTML代码:

复制代码
html>

<body>

<form id= "loginForm" >

<input name= "username" type= "text" />

<input name= "password" type= "password" />

<input name= "continue" type= "submit" value= "Login" />

<input name= "continue" type= "button" value= "Clear" />

<a href= "continue.html" >Continue</a>

</form>

</body>

</html>
复制代码

我们看看selenium提供了那些定位方式:

 

1. identifier定位

   这是最普遍的一种定位方式,当不能识别为其它定位方式后,默认为dientifier定位,在这种策略下,第一个使用id的页面元素将被识别出来,如果没有使用指定id的元素,那么将识别第一个名字与指定条件相符的元素。

identifier识别html各项元素的定位策略如下:

identifier=loginForm    //定位页面元素为from

identifier=username   //定位页面元素为username

identifier=Continue   //定位页面元素为Continue

因为identifier定位是默认方式,因此“identifier=” 可以不写。

Continue   //同样表示定位页面元素为Continue

 

2. id定位

这种定位方式比identifier定位范围更窄,当然也更具体,如果你知道元素id特征,就使用这种方式:

id=loginFrom   //定位页面元素from

 

3. name定位

名称定位方式将会识别第一个匹配名称属性的UI元素。如果多个元素拥有相同的名称属性,可以使用过滤器来进一步优化你的定位策略。默认的过滤器是Value (匹配value特征):

name=username   //定位页面元素为username

name=Continue  value=Clear  //定位页面元素为Continue ,值为Clear

name=Continue  type=button  //定位页面元素为Continue ,类型为button

 

提示:

上述三种定位器使得selenium可以不依赖于UI元素在页面上的位置而进行测试。所以,当页面结构发生变化时,测试依然可以通过。有时候,设计人员频繁改动页面的情况,通过id和name特征定位元素就变的非常重要。

 

4. XPath定位

XPath是一种在XML文档中定位元素的语言。因为HTML可以看做XML的一种实现,所以selenium用户可是使用这种强大语言在web应用中定位元素。

XPath扩展了上面id和name定位方式,提供了很多种可能性,比如定位页面上的第三个多选框。

xpath=/html/body/form[1]           //绝对路径(html的任何轻微改变都会导致失败)

//form[1]          //HTML中的第三个form元素

xpath=//form[@id=''loginForm'']        //id为loginFrom的元素

//input[@name=''username'']       //input元素且其name为‘username’

//form[@id=''loginForm'']/input[1]           //针对id为‘loginForm’的form,定位它的第一个input元素

//input[@name=''continue''][@type=''button'']         //name为‘continue’且type为‘button’的input

//form[@id=''loginForm'']/input[4]        //id为‘loingForm’的form,定位它的第四个input元素。

扩展阅读:

W3C XPath Recommendation: http://www.w3.org/TR/xpath/

XPath Tutorial: http://www.zvon.org/xxl/XPathTutorial/General/examples.html

http://www.w3.org/TR/xpath/

Firefox插件,可以帮助你获取页面元素的XPath:

XPath Checker         Firebug

 

5. 通过超链接定位

可以通过连接文字来定位超链,如果两个链接文字相同,那么第一个匹配的将被识别出来。

link=continue     //定位页面元素连接文字为continue

 

6. DOM定位

Document Object Model 被用于描述HTML文档,可以使用javaScript来访问。

这一定位策略通过javaScript评估页面上的元素,可以使用分级符号来简化元素定位。

      因为DOM定位以“document”开始,所以“dom=”标签并不是必须的。

dom=document.getElementById(''loginForm'')        // 定位页面元素form

dom=document.forms[''loginForm'']       // 定位页面元素form

dom=document.forms[0]        // 定位页面元素form

document.forms[0] .usernam      //定位页面元素username

document.forms[0] .elements[3]      //定位页面元素continue,它是form的第四个元素

 

7。 CSS定位

  CSS(Cascading Style Sheets)是一种语言,它被用来描述HTML和XML文档的表现。CSS使用选择器来为页面元素绑定属性。这些选择器可以被selenium用作另外的定位策略。

css=form#loginForm    //定位页面元素form

css=input[name="username"]       //定位页面元素username

css=input.required[type="text"]        //定位页面元素,其类型为text

css=input.passfield        //定位页面元素,其类型为password

css=#loginForm input[type="button"]        //定位页面元素,其类型为button

css=#loginForm input:nth-child(2)        //定位页面元素passfield,且它为from的第二个input子元素

扩展阅读:

http://www.w3.org/TR/css3-selectors/

提示:很多有经验的selenium用户推荐CSS定位方式,因为它比XPath更快。而且可以在HTML文件中找到更复杂的对象。

 

------------------------------------------------------------------------------

菜鸟提示:

    讲了这么多页面定位的方式,还是不明白干啥用的?

自动化测试,我们通过工具来完成手工操作,如果我们要点击一个按钮,我们认得那是一个按钮,如何让自动化工具也认得那是一个按钮呢?如何让工具认得是“确定”按钮,而不是“取消”按钮呢。那每个按钮都有不同的属性,也许属性完全相同但位置不同。我们要通过他们的特征描述它们,然后自动化工具才能根据我们的描述去找到它们。

       那么,转换到我们的自动化测试代码是什么样子呢?

//下面是在java代码的实现
selenium.click("元素属性的描述");
selenium.click("id=loginForm");
selemiun.click("name=Continue  value=Clear");
......

 -----------------------转

今天的关于selenium+ Webrat +selenium指南selenium+webdriver的分享已经结束,谢谢您的关注,如果想了解更多关于c# – 是否可以在不安装Selenium Server的情况下使用ISelenium / DefaultSelenium?、org.openqa.selenium.WebDriverBackedSelenium的实例源码、Robot Framework + Selenium2Library 环境下,结合 Selenium Grid 实施分布式自动化测试、selenium IDE(五)selenium 命令之定位页面元素的相关知识,请在本站进行查询。

本文标签: