selenium1.X web Test experience

简介javascript

Selenium 是一个健壮的工具集合,跨不少平台支持针对基于 web 的应用程序的测试自动化的敏捷开发。它是一个开源的、轻量级的自动化工具,很容易集成到各类项目中,支持多种编程语言,好比 .NET、Perl、Python、Ruby 和 Java™ 编程语言。css

利用 Selenium 测试 Ajax 应用程序java

Asynchronous JavaScript and XML (Ajax) 是一种用于建立交互式 web 应用程序的 web 开发技术。Ajax 应用程序的一个特征是,不会致使一次从新加载整个页面。相反,浏览器将具备一个对服务器的异步调用以得到数据,而且只刷新当前页面的特定部分。要提升 web 页面的交互性、响应速度和可用性,测试 Ajax 应用程序的过程须要一些改变。web

咱们首先刷新 web 页面,而后就是等待,直到异步调用完成。完成以后,能够继续进行验证。此时,出现适当等待时间的问题。chrome

一种选择是在测试应用程序中简单地暂停一段固定的时间,这在大多数状况下都是可行的。在有些状况下,好比说网络吞吐量很慢时,Ajax 调用在暂停一段特定的时间以后没有完成,会致使测试用例失败。另外一方面,若是暂停时间太长,会使得测试慢得不可接受。express

Selenium 提供了更为高效的处理等待的方式。一种可能作法是,使用类 com.thoughtworks.selenium.Wait 来等待一个元素或文本在页面上出现或消失。能够在 until() 函数中定义等待的退出条件,或者扩展 Wait 类来实现等待退出。清单 1 是使用 Wait 类的样例代码。它将在条件知足时中止等待,或者在超出最大等待时间时返回一个超时异常。编程


清单 1. 等待元素或文本出现浏览器

Wait wait = new Wait() {
	public boolean until() {
	return selenium.isElementPresent(locator);
	// or selenium.isTextPresent(pattern);
	}
};
wait.wait("", timeoutInMilliseconds);

 

另外一种选择是使用 Selenium 中的 waitForCondition 函数,一个 JavaScript 代码片断将被做为参数传递给该函数。一旦 Selenium 检测到条件返回为真,它将中止等待。您能够等待一些元素或文本出现或者不出现。JavaScript 能够运行在由 Selenium.browser.getCurrentWindow() 函数弹出的应用程序窗口中。清单 2 是检查窗口状态的样例代码。它只工做在 Firefox 中。安全


清单 2. 等待窗口就绪的状态服务器

String script = "var my_window = selenium.browserbot.getCurrentWindow();" 
script += "var bool;";
 script += "var readyState = (my_window.document.readyState);";
script += "if (readyState == 'complete'){";
script += "bool = 'true';";
script += "}";
script += "bool;";
selenium.waitForCondition(script, timeoutInMilliseconds);

如何支持 dojo 应用程序

Dojo 是一个经常使用的 JavaScript 工具包,用于构造动态 web 界面。使用 Selenium 测试 Dojo 应用程序时的一个关键点是认识 Dojo 小部件和记录它们的操做。做者定义的 Dojo 小部件处于抽象级别。页面运行时,会将 Dojo 小部件转换成基本的 HTML 代码。存在不少由 Dojo 自动生成的 HTML 代码,所以,Dojo 小部件的认识可能与传统 HTML 小部件有些不一样。

Dojo 小部件上执行的操做(包括文本字段、按钮复选框和单选按钮)可能与 HTML 小部件相同。可是,Dojo 在组合框上提供的日期选择器和其余额外的小部件可能须要特定的处理。


图 1. Dojo 组合框
展现带几个选项的组合框的屏幕快照

使用 Selenium IDE 来记录图 1 中提供的组合框上选中的操做。单击向下箭头,会出现一个下拉列表。选中第三项 Stack(SWG)。记录的脚本提供在图 2 中。


图 2. Selenium IDE 记录的脚本
展现 Selenium 所记录信息(好比鼠标单击)的屏幕快照

有时,只会由 IDE 生成第二行脚本。在这种状况下,添加单击箭头按钮的操做。对于上面的脚本,若是第一行被从新播放,那么它应该生成下拉列表。可是它不执行任何操做。对于多个 Dojo 小部件,单击并不真正执行单击操做。将 click(locator) 更改成 clickAt(locator, coordString) 或者 MouseDown(locator)MouseUp(locator)。

对于下拉列表,等待时间应该相加。像图 2 中展现的脚本同样,选中项的单击操做将会恰好在单击向下箭头按钮以后执行。它可能会由于下拉列表没有出现而失败。简单地添加一个 pause 命令,或者使用 waitFor 命令等待菜单项元素出现,并继续执行下一个命令。

修改后的将会自动化 Dojo 组合框上的选择的脚本展现在图 3 中。


图 3. 修改后的在 Dojo 组合框中进行选择的 IDE 脚本
屏幕快照展现 clickAt、waitForElement 和 ClickAt 命令已修改

RC 代码展现在清单 3 中。


清单 3. 自动化 Dojo 组合框中选择操做的 RC 代码

selenium.clickAt("//div[@id='widget_offeringType']/div/div",””);
selenium.waitForCondition("selenium.isElementPresent(\"offeringType_popup2\")", "2000");
selenium.clickAt("offeringType_popup2",””);



图 4. 日期选择器
展现日期选择器的常规月历视图的屏幕快照

对于图 4 中的日期选择器例子,执行的操做可能不会被 IDE 记录。编写以下面清单 4 所示的 RC 代码。


清单 4. 自动化选择的 RC 代码

//click on the date field by id you defined;
selenium.clickAt("dateBox",""); 
//wait for the drop down date box by id;
selenium.waitForCondition("selenium.isElementPresent(\"widget_dateBox_dropdown\")", \
"2000"); 
//click previous year 2008;
selenium.clickAt("//span[contains(@class,'dijitCalendarPreviousYear')]", "");
//click on the month increase; 
//previous month would contains  ‘dijitCalendarIncrease’.
selenium.clickAt("//img[contains(@class,'dijitCalendarIncrease')]","");
//click on the date such as 28 of current month; If you do not specify 
//the td with the attribute of current month class, it will click \
on the //first 28 of previous month;
selenium.click("//td[contains(@class,'dijitCalendarCurrentMonth')]/span[text()='28']");

 

如本例所示,Dojo 应用程序不能经过简单的 IDE 记录进行测试。这些脚本有可能不能经过测试。脚本中有一些丢失的操做,或者操做并不真正工做。脚本应该调整成可以在 IDE 和 RC 中顺利地执行。对于复杂的 Dojo 小部件,一种可能的解决方案是使用 runScript(String) 函数,由于 Selenium 对 JavaScript 提供很好的支持。清单 5 提供一个 JavaScript 语句来模拟组合框选择。


清单 5. 运行 JavaScript 语句在组合框上进行选择

selenium.runScript("dijit.byId(\"offeringType\").setValue(\"Stack(SWG)");");

如何利用 Ant 构建 Selenium 测试

诸如 Ant 这样的集成工具能够方便地构建 Selenium 测试和顺畅地运行测试用例,无需单独启动 Selenium 服务器。若是 Selenium 测试由 TestNG 驱动,那么定义清单 6 所示 TestNG Ant 任务。清单 6 中假设 classpath 是 TestNG.jar 文件的文件路径。


清单 6. TestNG Ant 任务

<taskdef resource="testngtasks" classpath="testng.jar"/>       

 

主要的目标是启动服务器、运行测试,而后中止服务器。这些任务按照 bulid.xml 中定义的顺序实如今清单 7 中。


清单 7. 启动服务器、运行测试用例并中止服务器的 Ant 任务

<target name="run_test" description="start,run and stop" depends="dist">
<parallel>
 <antcall target="start-server" /> 
<sequential>
 <echo taskname="waitfor" message="Waitforproxy server launch" /> 
 <waitfor maxwait="2" maxwaitunit="minute" checkevery="100">
 <http url="http://localhost:4444/selenium-server/driver/?cmd=testComplete" /> 
 </waitfor>
 <antcall target="runTestNG" /> 
 <antcall target="stop-server" /> 
 </sequential>
 </parallel>
 </target>

 

代码更可取的地方是使用 waitfor 任务来测试 Selenium 服务器是否已成功启动,而不是暂停一段固定的时间。若是 URL http://localhost:4444/selenium-server/driver/?cmd=testComplete 可用,就意味着 Selenium 已经成功启动。在清单 7 中,它最多等待两分钟,而且每 100 毫秒在本地主机上检查一次 Selenium 服务器,以提供完整的 URL。

start-server 任务的详细内容定义在清单 8 中。Firefox profile 模板位置和其余参数能够指定在标记 <arg> 中。


清单 8. 详细的启动服务器的 Ant 任务

<target name="start-server">
<java jar="lib/selenium-server.jar" fork="true">
 <arg line="-firefoxProfileTemplate ${selenium}/profile/" /> 
 </java>
 </target>

 

runTestNG 任务的详细内容定义在清单 9 中。testng 任务的经常使用属性包括 outputDirxmlfileset。属性 outputDir 用于设置输出报告位置。属性 xmlfileset 用于包含启动 XML 文件。更多选项请参考 TestNG 正式网站。


清单 9. 运行测试用例的 Ant 任务

<target name="runTestNG">
<testng outputDir="${testng.report.dir}" sourcedir="${build}" 
classpathref="run.cp" haltOnfailure="true">
 <xmlfileset dir="${build}" includes="testng.xml" /> 
 </testng>
 </target>

 

stop-server 任务的详细内容定义在清单 10 中。


清单 10. 中止 Selenium 服务器的 Ant 任务

<target name="stop-server">
 <get taskname="selenium-shutdown" 
src="http://localhost:4444/selenium-server/driver/?cmd=shutDown" ignoreerrors="true" /> 
 <echo taskname="selenium-shutdown" message=" Errors during shutdown are expected" /> 
 </target>

 

上面列出了关键任务。将它们组合到您的构建文件,以便利用 Ant 完成良好集成的测试。

如何支持测试 HTTPS 网站

随着互联网日益强调信息安全,愈来愈多的 web 应用程序在使用 SSL 身份认证。Selenium IDE 默认支持 HTTPS,可是 Selenium RC 不是这样的。Internet Explorer 和 Firefox 中的解决方案各不相同。

对于 IE,在 setup 目录下的 SSL 支持文件夹中在安装一个证书。若是使用的版本早于 Selenium-RC 1.0 beta 2,请使用 *iehta 运行模式,对于 Selenium-RC 1.0 beta 2 或更晚的版本,使用 *iexplore 运行模式。

若是测试 HTTPS 网站时出现一个以下所示的安全警告,那么单击 View Certificate 并安装 HTTPS 网站的证书。若是继续弹出警告,那么考虑在 IE 中进行配置。打开 Tool > Internet Options > Advanced,并取消选择 security 分类下的 Warn about invalid site certificatesCheck for publisher's certificate revocation


图 5. 测试 HTTPS 网站时的安全警告
展现指出证书未证明的 Security Alert 的屏幕快照

建立新的 Firefox 配置文件

对于 Firefox,遵循如下步骤建立定制的配置文件,而后重启服务器:

  1. 关闭任何正在运行的 Firefox 实例。
  2. 利用配置文件管理器 firefox -ProfileManager 启动 Firefox。
  3. 建立一个新的配置文件。出现提示时,为配置文件选择一个目录。将它放在项目文件夹里面。
  4. 选择配置文件并运行 Firefox。
  5. 利用您将用于测试的自签名证书导航到 HTTPS URL。 出现提示时接受证书。这将在配置文件中建立一个异常。
  6. 关闭浏览器。
  7. 转到 Firefox 配置文件目录。
  8. 删除该目录中除 cert_override.txtcert8.db 文件以外的任何东西。

默认状况下,Selenium 将在启动 Firefox 的实例时建立一个新的配置文件。当您利用参数 -firefoxProfileTemplate /path/to/profile/dir 启动服务器时,Selenium 将使用一个部分配置文件(带有证书异常)做为建立新配置文件的基础。这将提供证书异常,而避免了使用整个配置文件带来额外的混乱。注意一下在 Selenium RC 1.0 Beta 2 或更晚版本中以 *firefox 模式,以及在 Selenium RC 1.0 Beta 2 以前的版本中以 *chrome 模式启动 Firefox。

对于运行模式,*chrome*iehta 是较早版本 Selenium RC 中支持 HTTPS 和安全弹出处理的实验模式。自 Selenium-RC 1.0 beta 2 起,它们已经稳定成 *firefox*iexplore 运行模式。请谨慎地根据所使用的 Selenium 版本而使用运行模式。

如何高效地认识不带 ID 属性的 web 元素

使用一个有含义的 ID 或名称是一种高效且方便的定位元素的方式。它也能够改善测试用例的可读性。可是为了每一个元素具备一个有含义的、唯一的 ID(尤为是动态元素),Selenium 提供多种策略来认识元素,好比说 Xpath、DOM 和 CSS。

下面是一个样例,使用三种策略来定位图 6 中提供的动态表格中的一个元素。HTML 代码在清单 11 中。


图 6. 动态表格样例
展现动态建立的简单表格(带有两列和编辑连接)的屏幕快照


清单 11. 第一个表格列的 HTML 代码

<table id="test_table" border="1">
		<tbody>
        <tr>
            <td align="left">
                <div class="test_class">Test 1</div>
            </td>
            <td align="center" style="vertical-align: top;">
                <table id="AUTOGENBOOKMARK_4">
                    <tbody>
                        <tr>
                            <td align="center" style="vertical-align: top;">
                                <div>
                                  <img alt="supported" src="supported.png"/>
                                </div>
                            </td>
                            <td align="center" style="vertical-align: top;">
                                <div>
                                   <a href="test?name=test1">edit</a>
                                </div>
                            </td>
	…….

 

Xpath 是一种找到不带特定 ID 或名称的元素的简单方式。

  • 若是知道 ID 或名称以外的一个属性,那么直接使用 @attribute=value 定位元素。
  • 若是只知道属性值的一些特定部分,那么使用 contains(attribute, value) 定位元素。
  • 若是元素没有指定的属性,那么利用 Firebug 搜索最近的具备指定属性的父元素,而后使用 Xpath 从这个元素开始定位想要找到的那个元素。


表 1. 定位元素的 Xpath 表达式

定位元素 Xpath 表达式
n 行的第一列 //table[@id='test_table']//tr[n]/td
n 行的图像 //table[@id='test_table']//tr[n]//img
‘Test 1’ 的编辑连接 //a[contains(@href,test1)]

 

表 1 展现了定位元素的 Xpath 表达式。在 Firebug 的帮助下,Xpath 能够定位元素和复制的元素。在元素没有 ID 和名称时,Selenium IDE 将会采用 Xpath。尽管 Xpath 利用已经录的脚本,有助于保持一致性,可是它高度依赖于 web 页面的结构。这使得测试用例可读性差,增长了维护难度。此外,在 Internet Explorer 7 和 Internet Explorer 8 中运行具备多个复杂 Xpath 表达式的测试用例可能会太慢了。在这种状况下,将 Xpath 更换为 DOM,后者是另外一种高效的定位策略。

DOM 是 Document Object Model(文档对象模型)的缩写。Selenium 容许您利用 JavaScript 遍历 HTML DOM。Java 的灵活性容许在 DOM 表达式中有多个语句,用分号隔开,以及在语句中定义函数。


表 2. 定位元素的 DOM 表达式

定位元素 DOM 表达式
n 行的第一列 dom=document.getElementById('test_table').rows[n-1].cells[0]
n 行的图像 dom=element=document.getElementById('test_table').rows[n-1].cells[1]; element.getElementsByTagName('IMG')[0]
‘Test 1’ 的编辑连接
dom=function test(){
var array=document.getElementsByTagName('a');
var element;for(var i=0; i<array.length; i++)
{if(array[i].attributes.getNamedItem("href").\
value.indexOf('test2')!=-1){element=array[i];break;}}return element}; test()

 

表 2 展现了定位元素的 DOM 表达式。DOM 定位器在 Firefox 和 Internet Explorer 中也有很好的性能。组织 DOM 表达式须要一些 JavaScript 知识。有时,DOM 表达式对于复杂的元素来讲太长了,难以看懂(参见表 2 中提到的 Test 1 的编辑连接的表达式)。

CSS 定位器用于利用 CSS 选择器选择元素。当 HTML 代码具备良好的样式时,能够高效地利用 CSS 定位器。样例表达式展现在表 3 中。


表 3. 定位元素的 CSS 表达式

定位元素 CSS 表达式
n 行的第一列 css=#test_table .test_class:nth-child(n)
n 行的图像
css=#test_table  tr:nth-child(n) > td:nth-child(2) > 
table td:nth-child(1) > div >  img

‘Test 1’ 的编辑连接 css=a[href*='test2']

 

通常来讲,选用熟悉的定位器表达式,并在脚本结构中保持一致。若是有多种表达式可执行,那么使用最高效的方式在 web 页面中定位元素。

如何处理弹出窗口

通常来讲,操做都是在由 Selenium 启动的主窗口中执行。若是您想在一个由 window.open 函数生成的新窗口中执行操做,那么将焦点更换到新窗口。在弹出窗口中执行操做以后,焦点返回到主窗口。处理弹出窗口的过程定义在清单 12 中。


清单 12. 处理弹出窗口的样例代码

//wait for the popup window with timeout;
selenium.waitForPopUp(windowname, timeout); 
//select the pop up window
selenium.selectWindow(popupWindowIdentifier);
//perform action on popup window and close the window;
.... 
//return to the main window use 'null' 
selenium.selectWindow(null);

 

windowname 是调用 window.open 函数的第二个参数。上面提到的 popupwindowIdentifier 是一个窗口标识符,能够是窗口 ID、窗口名称、title=the title of the windowvar=javascript variable。若是弹出窗口的属性未知,可是真的定义了,那么使用 getAllWindowIds()getAllWindowNames()getAttributeFromAllWindows() 函数来检索弹出窗口的属性。

在最新版的 Selenium RC 1.0.1 中,Selenium 添加了像 selectPopUp(String)deselectPopUp() 这样的方法,它们的功能在之前版本中由 selectWindow(String) 提供。


清单 13. 处理弹出窗口的弹出函数

//wait for the popup window with timeout;
selenium.waitForPopUp(“”, timeout); 
//same as selenium.selectWindow
selenium.selectPopUp(“”);
//perform action on popup window and close the window;
.... 
//same as selenium.selectWindow(null);
selenium.deselectPopUp();

 

清单 13 展现了处理弹出窗口最简单的方式。您能够保留 waitForPopUpselectPopUp 函数中的第一个参数为空。若是同时弹出多个窗口,请指定窗口属性。

如何处理上载/下载文件窗口

Selenium 使用 JavaScript 来模拟操做。所以,它不支持诸如上载窗口、下载窗口或身份认证窗口之类的浏览器元素。对于非主要窗口,配置浏览器跳过弹出窗口。


图 7. 安全信息窗口
展现 Security Information 弹出窗口的屏幕快照,指出页面包含安全的和不安全的条目

跳过图 7 中安全信息窗口的解决方案是打开 Tools > Internet Options > Custom Level。而后启用 Display mixed content

配置 Internet Explorer 跳过非主要窗口会减小或消除运行测试用例时没必要要的处理。可是若是配置了 Firefox,那么将它保存为新的配置文件,并利用定制的配置文件启动服务器。在关于测试 HTTPS 网站的一节中提到了这样作的缘由。

对于上载/下载窗口,最好是处理而不是跳过它们。为了不 Selenium 的局限性,一种建议是使用 Java 机器人 AutoIt 来处理文件上载和下载问题。AutoIt 被设计来自动化 Window GUI 操做。它能够认识大多数 Window GUI,提供不少 API,而且很容易转换为 .exe 文件,这样的文件能够直接运行或者在 Java 代码中调用。清单 14 演示了处理文件上载的脚本。这些脚本的步骤是:

  1. 根据浏览器类型肯定上载窗口标题。
  2. 激活上载窗口。
  3. 将文件路径放入编辑框中。
  4. 提交。


清单 14. 处理上载的 AutoIt 脚本

;first make sure the number of arguments passed into the scripts is more than 1 
If $CmdLine[0]<2 Then Exit EndIf
 handleUpload($CmdLine[1],$CmdLine[2])

;define a function to handle upload
 Func handleupload($browser, $uploadfile)
	 Dim $title                          ;declare a variable
            ;specify the upload window title according to the browser
            If $browser="IE" Then                  ; stands for IE;
 	      $title="Select file"
            Else                                 ; stands for Firefox
	       $title="File upload"
            EndIf
 
            if WinWait($title,"",4) Then ;wait for window with 
title attribute for 4 seconds;
                   WinActivate($title)                  ;active the window;
                   ControlSetText($title,"","Edit1",$uploadfile)   ;put the 
file path into the textfield  
                   ControlClick($title,"","Button2")                ;click the OK 
or Save button
            Else
	        Return False
            EndIf
 EndFunc 

 

在 Java 代码中,定义一个函数来执行 AutoIt 编写的 .exe 文件,并在单击 browse 以后调用该函数。


清单 15. 执行 AutoIt 编写的 .exe 文件

public void handleUpload(String browser, String filepath) {
	String execute_file = "D:\\scripts\\upload.exe";
	String cmd = "\"" + execute_file + "\"" + " " + "\"" + browser + "\""
				+ " " + "\"" + filepath + "\""; //with arguments
	try {
		Process p = Runtime.getRuntime().exec(cmd);
		p.waitFor(); //wait for the upload.exe to complete
	} catch (Exception e) {
		e.printStackTrace();
	}
}

 

清单 16 是处理 Internet Explorer 中下载窗口的 AutoIt 脚本。Internet Explorer 和 Firefox 中的下载脚本各不相同。


清单 16. 处理 Internet Explorer 中下载的 AutoIt 脚本

If $CmdLine[0]<1 Then Exit EndIf
handleDownload($CmdLine[1])
Func handleDownload($SaveAsFileName)
Dim $download_title="File Download" 
If WinWait($download_title,"",4) Then
    WinActivate($download_title)
    Sleep (1000)
    ControlClick($download_title,"","Button2","")
    Dim $save_title="Save As"
    WinWaitActive($save_title,"",4)
    ControlSetText($save_title,"","Edit1", $saveAsFileName)
    Sleep(1000)
    if FileExists ($SaveAsFileName) Then
	FileDelete($SaveAsFileName)
	EndIf
    ControlClick($save_title, "","Button2","")
    Return TestFileExists($SaveAsFileName)
Else
    Return False
EndIf
EndFunc

 

AutoIt 脚本很容易编写,可是依赖于浏览器类型和版本,由于不一样的浏览器和版本中,窗口标题和窗口控件类是不相同的。

如何验证警告/确认/提示信息

对于由 window.alert() 生成的警告对话框,使用 selenium.getAlert() 来检索前一操做期间生成的 JavaScript 警告的消息。若是没有警告,该函数将会失败。获得一个警告与手动单击 OK 的结果相同。

对于由 window.confirmation() 生成的确认对话框,使用 selenium.getConfirmation() 来检索前一操做期间生成的 JavaScript 确认对话框的消息。默认状况下,该函数会返回 true,与手动单击 OK 的结果相同。这能够经过优先执行 chooseCancelOnNextConfirmation 命令来改变。

对于由 window.prompt() 生成的提示对话框,使用 selenium.getPromt() 来检索前一操做期间生成的 JavaScript 问题提示对话框的消息。提示的成功处理须要优先执行 answerOnNextPrompt 命令。

JavaScript 警告在 Selenium 中不会弹出为可见的对话框。处理这些弹出对话框失败会致使异常,指出没有未预料到的警告。这会让测试用例失败。

相关文章
相关标签/搜索