用 Selenium 自动化测试
http://selenium.openqa.org/
http://www.ibm.com/developerworks/cn/java/wa-selenium-ajax/
Web 应用程序的验收测试常常涉及一些手工任务,例如打开一个浏览器,并执行一个测试用例中所描述的操作。但是手工执行的任务容易出现操作人员人为的错误,也比较费时间。因此,尽可能将这些任务自动化,以消除人为因素,这是一种很好的做法。于是 Selenium 之类的测试工具就有了用武之地。Selenium 帮助您自动化验收测试,从而可以构建经过更严格测试、因而更为可靠也更易于维护的软件。
Ajax
Ajax 是 Asynchronous JavaScript and XML 的缩写,这是为相当老的技术新创造的一个术语。Ajax 背后的主要思想是,由于只需更新部分页面而不是整个页面,所以 Web 应用程序可以更快地对用户操作做出响应。
Ajax 将更多的复杂性引入到 Web 应用程序中,这一点也反映在测试中。这是因为 Ajax 就像它的名称所表明的那样,使用 JavaScript 和异步 HTTP 请求来更新页面内容。每个浏览器在实现中与其他浏览器相比有一些小小的不同。Selenium 是测试和检测这些差异的很好的工具,因为它在大多数流行的浏览器中都能够运行。
什么是 Selenium?
Selenium 是 ThoughtWorks 专门为 Web 应用程序编写的一个验收测试工具。据 Selenium 主页所说,与其他测试工具相比,使用 Selenium 的最大好处是:
Selenium 测试直接在浏览器中运行,就像真实用户所做的一样。Selenium 测试可以在 Windows、Linux 和 MacintoshAnd 上的 Internet Explorer、Mozilla 和 Firefox 中运行。其他测试工具都不能覆盖如此多的平台。
使用 Selenium 和在浏览器中运行测试还有很多其他好处。下面是主要的两大好处:
通过编写模仿用户操作的 Selenium 测试脚本,可以从终端用户的角度来测试应用程序。
通过在不同浏览器中运行测试,更容易发现浏览器的不兼容性。
Selenium 的核心,也称 browser bot,是用 JavaScript 编写的。这使得测试脚本可以在受支持的浏览器中运行。browser bot 负责执行从测试脚本接收到的命令,测试脚本要么是用 HTML 的表布局编写的,要么是使用一种受支持的编程语言编写的。
Selenium 适用于以下浏览器:
Internet Explorer Mozilla Firefox Safari
Windows XP 6.0 1.6+, 1.7+ 0.8+, 0.9+, 1.0
Red Hat Linux 1.6+, 1.7+ 0.8+, 0.9+, 1.0+
Mac OS X 10.3 不支持 1.6+, 1.7+ 0.8+, 0.9+, 1.0+ 1.3+
Selenium 命令
通过 Selenium 命令,脚本编写者可以描述 browser bot 在浏览器中所执行的操作。可以将这些命令分成两类 —— 操作(action) 和断言(assertion):
操作模拟用户与 Web 应用程序的交互。例如,单击一个按钮和填写一个表单,这些都是常见的用户操作,可以用 Selenium 命令来自动化这些操作。
断言验证一个命令的预期结果。常见的断言包括验证页面内容或当前位置是否正确。
在 Selenium 网站上可以找到可用命令的完整列表(见 参考资料)。
Selenium 模式
可以按两种模式来使用 Selenium:test runner 和 driven。这两种模式在复杂性和编写方式方面有所不同。driven 测试脚本编写起来往往要更复杂一些,因为它们是用编程语言编写的。但是如果使用 Python 或 Ruby 之类的高级动态编程语言,那么这种复杂性方面的差异就很小。
两种模式之间最大的不同点在于,如果使用 driven 脚本,测试有一部分在浏览器之外运行,而如果使用 test runner 脚本的话,测试是完全在浏览器中运行的。
不管是 test runner 还是 driven 测试用例,都可以与持续集成工具集成。
test runner 模式
Selenium test runner 脚本,也称测试用例(test case),是用 HTML 语言通过一个简单的表布局编写的,如 清单 1 所示。
清单 1. Selenium 测试用例的结构
<table border="1">
<tr>
<td>First command</td>
<td>Target</td>
<td>Value</td>
</tr>
<tr>
<td>Second command</td>
<td>Target</td>
<td>Value</td>
</tr>
</table>
test runner 脚本通常与所测试的应用程序(AUT)部署在同一个服务器上。这是因为 browser bot 使用 JavaScript 来模拟用户操作。这些脚本在一个受限制的沙箱环境中运行。如果需要绕过这些限制,可以使用一个代理。
test runner 脚本使用与 xUnit 框架相同的测试套件(test suite)和测试用例概念。测试用例和命令按照它们在测试套件和测试用例中出现的顺序依次执行。在 清单 1 中:
第一列包含命令 或断言。
第二列包含命令或断言的目标(target)。这里可以用多种受支持的组件定位符中的一种来指定目标。通常使用的是组件的 ID 或名称,但 XPath 和 DOM 定位符也是受支持的。
第三列包含用于为命令或断言指定参数的值。例如,当使用 type 命令时,这一列可能就是一个文本域所期望的值。
即使对于非技术人员来说,test runner 脚本也易于阅读和编写。当在一个浏览器中打开 清单 1 中的例子时,将得到类似这样的一个表:
First command Target Value
Second command Target Value
接下来,我将描述如何使用命令和断言编写一个简单但是完整的测试用例。
测试用例实例
执行 清单 2 中的测试脚本时,它将执行以下操作:
通过进入 /change_address_form.html 打开变更地址页面。
在 ID 为 address_field 的文本框中输入 Betelgeuse state prison。
单击名为 Submit 的输入区。注意,这里使用 XPath 找到 Submit 按钮,这导致表单数据被发送到服务器。
验证页面是否包含文本 Address change successful。
清单 2. 在测试用例中使用命令和断言的例子
<table>
<tr>
<td>open</td>
<td>/change_address_form.html</td>
<td></td>
</tr>
<tr>
<td>type</td>
<td>address_field</td>
<td>Betelgeuse state prison</td>
</tr>
<tr>
<td>clickAndWait</td>
<td>//input[@name='Submit']</td>
<td></td>
</tr>
<tr>
<td>verifyTextPresent</td>
<td>Address change successful</td>
<td></td>
</tr>
</table>
测试套件
要达到对应用程序的完全测试覆盖,通常需要不止一个测试用例。这就是 Selenium 使用测试套件的原因。测试套件用于将具有类似功能的一些测试用例编成一组,以便让它们按顺序运行。
测试套件和测试用例一样,都是用简单的 HTML 表编写的。Selenium 执行的缺省测试套件的名称是 TestSuite.html。清单 3 展示了一个测试套件,该套件像通常的用户一样测试应用程序。注意,测试套件使用一个只包含一列的表,表中的每一行指向一个包含某个测试用例的文件。
清单 3. 测试套件示例
<table>
<tr>
<td>Test suite for the whole application</td>
</tr>
<tr>
<td><a href="test_main_page.html">Access main page</a></td>
</tr>
<tr>
<td><a href="test_login.html">Login to application</a></td>
</tr>
<tr>
<td><a href="test_address_change.html">Change address</a></td>
</tr>
<tr>
<td><a href="test_logout.html">Logout from application</a></td>
</tr>
</table>
接下来我将把目光转移到 driven 测试脚本。
driven 模式
driven Selenium 脚本是用多种受支持的编程语言中的一种编写的 —— 目前可用的有 Java、Ruby 和 Python 驱动程序。这些脚本在浏览器之外的一个单独的进程中运行。驱动程序的任务是执行测试脚本,并通过与运行在浏览器中的 browser bot 进行通信来驱动浏览器。驱动程序与 browser bot 之间的通信使用一种简单的特定于 Selenium 的连接语言 Selenese。
driven 脚本比 test runner 脚本更强大、更灵活,可以将它们与 xUnit 框架集成。driven 脚本的缺点(与 test runner 脚本相比)是,这种脚本编写和部署起来更复杂。这是因为驱动程序必须执行以下任务:
启动服务器。
部署所测试的应用程序(AUT)。
部署测试脚本。
启动浏览器。
发送命令到 browser bot。
验证 browser bot 执行的命令的结果。
driven 脚本更依赖于应用程序运行时环境。例如,Java 驱动程序使用一个嵌入式 Jetty 或 Tomcat 实例来部署所测试的应用程序。目前,已经有人在致力于将 Selenium 集成到 Ruby on Rails 中,但是在我撰写本文之际,这个集成版本还没有被发布。
清单 4 摘自一个使用 Ruby 驱动程序的 driven 测试脚本。注意,我省略了用于启动服务器和浏览器的步骤,这个测试脚本代码几乎和 test runner 脚本一样简单。
清单 4. 使用 Ruby 驱动程序的例子
.
.
puts selenium.open('/logout.html')
puts selenium.verify_location('/index.html')
.
.
---------------
对于希望将自己的测试整合到一个持续集成的工具中的开发者而言,最大的喜讯莫过于,他们可以用自己喜欢的语言(如C#、JAVA、VB.NET、Ruby或者Python等)来编写测试,并利用Selenium的一个名为Selenium RC的扩展实现整合。
Selenium Remote Control (RC) is a test tool that allows you to write automated web application UI tests in any programming language against any HTTP website using any mainstream JavaScript-enabled browser.
Selenium RC comes in two parts.
A server which automatically launches and kills browsers, and acts as a HTTP proxy for web requests from them.
Client libraries for your favorite computer language.
The RC server also bundles Selenium Core, and automatically loads it into the browser.
Here is a simplified architectural representation....
The Selenium Server is great for testing complex AJAX-based web user interfaces under a Continuous Integration system. It is also an ideal solution for users of Selenium Core or Selenium IDE who want to write tests in a more expressive programming language than the Selenese HTML table format customarily used with Selenium Core.
Selenium-RC: Tutorial
http://selenium-rc.openqa.org/tutorial.html
需要安装Java运行环境 JRE
http://java.sun.com
JRE 6 update7
\\10.10.10.8\public\Softwares\jre-6u7-windows-i586-p.exe
Selenium RC FAQ
http://wiki.openqa.org/display/SRC/Selenium+RC+FAQ
中文帮助网页
http://wiki.javascud.org/display/SEL/Home
--------------
Interactive Mode
http://selenium-rc.openqa.org/tutorial.html
交互模式
java -jar selenium-server.jar -interactive
多窗口模式
java -jar selenium-server.jar -multiWindow
显示:
Entering interactive mode... type Selenium commands here (e.g: cmd=open&1=http://www.yahoo.com)
输入如下命令:
cmd=getNewBrowserSession&1=*iexplore&2=http://www.google.com
显示:
18:33:06.921 INFO - Allocated session 8b959f439f8140a5a9349039aa232e95 for http://www.google.com, launching...
18:33:12.234 INFO - Got result: OK,8b959f439f8140a5a9349039aa232e95 on session 8b959f439f8140a5a9349039aa232e95
获得sessionId:8b959f439f8140a5a9349039aa232e95
输入如下命令:
cmd=open&1=http://www.google.com/webhp&sessionId=8b959f439f8140a5a9349039aa232e95
输入如下命令:
cmd=type&1=q&2=hello world&sessionId=8b959f439f8140a5a9349039aa232e95
输入如下命令:
cmd=click&1=btnG&sessionId=8b959f439f8140a5a9349039aa232e95
输入如下命令:
cmd=getTitle&sessionId=8b959f439f8140a5a9349039aa232e95
输入如下命令:
cmd=testComplete&sessionId=8b959f439f8140a5a9349039aa232e95
-------------
Selenium-RC: Using the .NET Client Driver
already started the Selenium Server
打开Selenium服务器
To use the .NET Client Driver in Visual Studio, just add the ThoughtWorks.Selenium.Core.dll assembly as a reference to your VS project, and create a new DefaultSelenium object. You'll need to give it the hostname and port of the Selenium Server, the browser string to use with "getNewBrowserSession", and the base URL at which we'll start testing. When you're ready to begin, run the .start() method on your DefaultSelenium object; when it's time to close the browser, use the .stop() method.
把dll文件导入VS项目,引用Selenium的命名空间。
Selenium.DefaultSelenium Brower = new Selenium.DefaultSelenium("localhost", 4444, "*iexplore", "http://www.google.com");
Brower.Start();
Brower.Open("http://www.google.com/webhp");
Brower.Type("q", "hello world");
Brower.Click("btnG");
Selenium-RC: Using the Java Client Driver
already started the Selenium Server
打开Selenium服务器
Just add selenium-java-client-driver.jar to your classpath, and create a new DefaultSelenium object. You'll need to give it the hostname and port of the Selenium Server, the browser string to use with "getNewBrowserSession", and the base URL at which we'll start testing. When you're ready to begin, run the .start() method on your DefaultSelenium object; when it's time to close the browser, use the .stop() method.
用Eclipse来举例
1. 先去 http://selenium-rc.openqa.org/download.jsp 下载selenium包。解压。
2. 用命令行来到解压的文件夹下: \selenium-server-1.0-beta-1
3. 运行: java -jar selenium-server.jar 启动selenium server
4. 在Eclipse创建一个项目,在项目的build path里面加上junit.jar和selenium-java-client-driver.jar(这个在刚解压的包里面)
5. 在项目里面新建一个junit文件,比如说openQA这个网站上的GoolgeTest文件
6. 在红色波浪线的那些地方,比如Selenium, DefaultSelenium上面‘Ctrl+1’来增加相应要import的类
7. 然后在Eclipse里运行 “Run As -> unit Test”即可看到自动化的范例
import com.thoughtworks.selenium.DefaultSelenium;
import com.thoughtworks.selenium.Selenium;
public class GoogleTest {
public static void main(String[] args) {
Selenium selenium=new DefaultSelenium("localhost", 4444, "*iexplore", "http://www.google.com");
selenium.start();
selenium.open("http://www.google.com/webhp?hl=en");
System.out.print("Hello World!");
}
}
最后粘贴一下那个测试程序GoogleTest.java
import com.thoughtworks.selenium.DefaultSelenium;
import com.thoughtworks.selenium.Selenium;
import junit.framework.TestCase;
public class GoogleTest extends TestCase {
private Selenium selenium;
public void setUp() throws Exception {
String url = "http://www.google.com";
selenium = new DefaultSelenium("localhost", 4444, "*firefox", url); //4444 is default server port
selenium.start();
}
protected void tearDown() throws Exception {
selenium.stop();
}
public void testGoogle() throws Throwable {
selenium.open("http://www.google.com/webhp?hl=en");
assertEquals("Google", selenium.getTitle());
selenium.type("q", "Selenium OpenQA");
assertEquals("Selenium OpenQA", selenium.getValue("q"));
selenium.click("btnG");
selenium.waitForPageToLoad("5000");
assertEquals("Selenium OpenQA - Google Search", selenium.getTitle());
}
}
Selenium API
http://selenium-core.openqa.org/reference.html
Wait的使用:
FAQ:http://wiki.openqa.org/display/SRC/Selenium+RC+FAQ#SeleniumRCFAQ-HowcanIpauseuntilanelementiscreated%28e.g.%2CinanAJAXappwherethepagehasalreadyloaded%2Cbutapartialinplacerefreshwillcreateanelement%29%3F
Automate Website Testing with Selenium RC
http://www.alvinsingh.org/blog/2008/05/automate-website-testing-with-selenium-rc/
等待控件出现后再进行操作:
protected static Selenium selenium;
......
new com.thoughtworks.selenium.Wait() {
public boolean until() {
return selenium.isElementPresent("main");
}
}.wait(timeoutMessage);