1.概述
Selenium是非常非常有用的,对JavaScript支持良好的Web层功能测试,集成测试工具。
Selenium分为Core与RC(Remote Controll)两个部分,其中Core是基础的,直接在HTML Table里编写测试代码的模块,而Remote Controll则支持用Java等语言编写测试用例,并自动调用FireFox1.5来运行。
具体的语法见http://www.openqa.org/selenium-core/usage.html
2.Better Practice
1. Never use Selenium FIT mode
Selenium分为两种运行模式,Driven Mode(现在叫Selenium Remote Control)和FIT Mode(现在叫Selenium Core)。
FIT Mode顾名思义,就是类似FIT Testing Framework那种使用方式,主要用于QA等非技术人员编写Web应用的功能测试。FIT Mode的Selenium测试使用HTML来组织测试用例。例如我要测试一个web应用的登陆功能。我可能写出这样的HTML 表格。
1 <table>
2 <tr>
3 <td>open</td>
4 <td>http://localhost:8080/login</td>
5 <td></td>
6 </tr>
7 <tr>
8 <td>type</td>
9 <td>id=username</td>
10 <td>someuser</td>
11 </tr>
12 <tr>
13 <td>type</td>
14 <td>id=password</td>
15 <td>password</td>
16 </tr>
17 <tr>
18 <td>click</td>
19 <td>id=login_button</td>
20 <td></td>
21 </tr>
22 <tr>
23 <td>assertTextPresent</td>
24 <td>Welcome to xxxx</td>
25 <td></td>
26 </tr>
27 </table>
不同于FIT,Selenium内置了一系列的命令,如上例中的open, type, click以及assertTextPresent,因此QA可以完全抛开DEV独立地编写测试(FIT需要DEV提供Behavior Fixture)。因此FIT Mode是相当容易使用的,哪怕不会使用HTML的QA,也可以使用FrontPage画出三列表格,依次填入数据。
然而对于大多数team而言——尤其是敏捷team,FIT Mode平易的外表下是令人恐惧的泥沼。大多数团队往往选择使用Selenium作为功能测试和集成测试工具而不仅仅是QA测试工具,在不同的迭代间遇到功能流程或UI变化时,必须要重构Selenium测试,或者说,FunctionalTest Migration。令人遗憾的是,HTML based的Selenium FIT Testing的重构竟然令人难以置信的困难。我们可以使用include等Selenium FIT扩展,使得它可以重用详细的功能(Log in, Log out诸如此类)。即便如此,在一个真实的项目中,Selenium Test的数量往往在200-500之间(我目前所处的项目在改用Driven Mode前已达350+),对于这么大基数的Selenium测试,手工重构几乎是不可想象的,而目前尚没有HTML代码重构工具。即便存在泛泛意义上的HTML重构工具,对于Selenium测试重构的有效性尚待商榷。而使用Driven Mode上述代码可以写为:
1 public void testShouldShowAWeclomeMessageAfterUserLoggedIn() {
2 selenium.open("http://localhost:8080/login");
3 selenium.type("id=username","someuser");
4 selenium.type("id=password", "password");
5 selenium.click("id=login_button");
6 assertTrue(selenium.isTextPresent("Welcome to xxxx"));
7}
很自然,一个训练有素的程序员会重构出如下代码:
1 public void login(String username, String password) {
2 selenium.open("http://localhost:8080/login");
3 selenium.type("id=username",username);
4 selenium.type("id=password", password);
5 selenium.click("id=login_button");
6}
7
8 public void testShouldShowAWeclomeMessageAfterUserLoggedIn() {
9 login("someuser", "password");
10 assertTrue(selenium.isTextPresent("Welcome to xxxx"));
11}
之后无论是pull up到公共基类还是extact到Utils class都是很容易的事情。由于Java在代码重构上便利,Java Selenium Remote Control成为使用Selenium的最佳方式。在这一点上,纵使Ruby语法上比Java简单灵活得多,它仍不是编写Selenium测试的最佳载体(当然一个经过精心设计的ruby selenium dsl wrapper还是具有非凡的价值的,这个我们后面会涉及到)。
2. Using the name user, system, page instead of selenium
观察上面提到的代码,其中使用selenium来操纵web应用的行为,这在Remote Control里是常见的做法,但是仍然不够好,我们可以做一些小的变化以得到更好的测试:
1 protected void setup() {
2 selenium = // intialize selenium instance
3 user = selenium;
4 currentPage = selenium;
5}
6
7 public void login(String username, String password) {
8 user.open("http://localhost:8080/login");
9 user.type("id=username",username);
10 user.type("id=password", password);
11 user.click("id=login_button");
12}
13
14 public void testShouldShowAWeclomeMessageAfterUserLoggedIn() {
15 login("some guy", "password");
16 assertTrue(currentPage.isTextPresent("Welcome to xxxx"));
17}
基本上这只不过是"另一种写法"而已,但是它更好的表达了"用户的行为",如login代码所示。以及"系统的正确相应",即currentPage.isTextPresent()。这种是典型的对编译器无意义对人有意义的代码,也就是普遍意义上好的代码。
3. Creating a DSL base on your test codes
懂得HTML的QA可以在没有DEV的帮助下使用Selenium FIT mode,然而却不能在没有DEV的帮助下使用Driven Mode。于是最自然也是最fashion的做法,就是在已有的test codes之上提供Testing DSL或者Scripting Language,让FIT mode变得更加FIT。这方面内容是一个更大的主题,以后再详细展开吧。
4. Hacking Selenium Object to support FIT command
Selenium FIT mode和RC mode下的命令有些许差异,比如FIT中的assertTextPresent,在RC中变成了isTextPresent。同样还有FIT中最实用的命令clickAndWait,在RC中变成了click和waitForPageToLoad。在RC中使用FIT mode中的命令也非难事,找到com.thoughtworks.selenium.Selenium,添加方法:
public void doCommand(String commmand, String parameters);
然后在com.thoughtworks.selenium.DefaultSelenium中添加实现:
1 public void doCommand(String commmand, String parameters) {
2 String[] paras = new String[] {"","",""}
3 for (int i = 0; i < parameters.length && i < 3; i++)
4 paras[i] = parameters[i];
5 commandProcessor.doCommand(command, paras);
6}
然后试验一下:
selenium.doCommand("clickAndWait");
在我们使用纯RC mode之前曾经用过一段中间方案,将rc code转化为fit code来跑(因为rc不支持https),由于不是真正的rc mode,像isTextPresent之类的方法都没有办法使用,只能使用FIT mode command。因此如果因为一些特殊的原因(https, chrome起不来,hta bug多等等),你没有办法使用RC mode,但是有希望得到RC可重构的好处,那么这个tricky的技巧倒是不错的选择。
5. Using chrome and IE hta lanucher to support https
6. Run test using different browser lanucher to test browser compatibility
这两个都是和browser lanucher相关的,Selenium和JWebUnit最大的不同在于它使用真实的浏览器来跑测试,从而可以更加真实地考察系统在不同浏览器中的表现。因此使用不同的浏览器lanucher来运行测试,可以更好测试应用的浏览器兼容性,这对于web 2.0应用而言是很有帮助的。此外,使用rc提供的试验性lanucher,chrome和hta可以解决跨domain测试和https的问题。不过目前hta还是有很多bug的,推荐使用chrome。当然,最希望的还是澳洲的同事可以早日在selenium里提供https支持。