在Selenium1.0处于开发阶段的同时,另一款浏览器自动化框架WebDriver也正在ThoughtWorks公司的酝酿之中。WebDriver项目的初衷是把端对端测试与底层测试工具隔离开。通常情况下,这种隔离手段通过适配器(Adapter)模式完成。WebDriver正是来源于该方法在许多项目上的不断实践应用,初是HtmlUnit的封装,工具发布后很快开始支持Internet Explorer和Firefox。WebDriver的初代码在2007年初发布。
在WebDriver初发布时,与Selenium RC存在显著差异,尽管它们都属于浏览器自动化的API工具。对于用户来说,明显的区别在于Selenium RC提供基于字典的API,所有方法都在一个类中开放,而WebDriver的API更面向对象。此外,WebDriver仅支持Java,而Selenium RC提供广泛的语言支持。技术差异也很明显:Selenium Core(RC的基础)基本上是JavaScript应用,运行在浏览器的安全沙箱之内。WebDriver则尝试原生绑定到浏览器中,绕开了浏览器的安全模型,代价是框架自身的开发投入显著增加。
在2009年8月,两个项目宣布合并,Selenium WebDriver是合并的成果。
WebDriver的创建者Simon Stewart早在2009年8月的一份邮件中解释了项目合并的原因:
为何把两个项目合并?部分原因是WebDriver解决了Selenium存在的缺点(比如,能够绕过JS沙箱。我们有出色的API),部分原因是Selenium解决了WebDriver存在的问题(例如支持广泛的浏览器),部分原因是因为Selenium的主要贡献者和我都觉得合并项目是为用户提供框架的佳途径。
目前,WebDriver支持的语言绑定包括Java、C#、Python和Ruby。它支持Chrome、Firefox、Opera和移动端Android、iPhone浏览器。此外,还有其他关联项目,不在同一源代码库中维护,但是和主项目(Selenium WebDriver)紧密合作,例如提供Perl绑定支持、BlackBerry浏览器支持,以及“无头”WebKit——用于持续集成的测试其无法正常显示的情况。初的Selenium RC机制仍然维持,帮助WebDriver在浏览器不受支持的情况下提供支持。
在两个项目合并中出现了哪些架构方面的问题?学到了哪些经验和教训?Simon Stewart在《The Architecture of Open Source Applications》一文中做了详细的描述,本文参考了以下内容:
http://www.aosabook.org/en/selenium.html
http://www.infoq.com/cn/news/2011/07/selenium-arch-2
处理复杂性
软件是模块构造起来的。这些模块很复杂,作为API的设计人员们,可以选择如何处理这种复杂性。极端情况下,可能会传播这种复杂性,这意味着API的每一位用户都需要牵涉其中。另一个极端情况是承担尽可能多的复杂性并将其隔离在某个地方。这个地方对于许多想一探究竟的API用户来说黑暗而恐怖。折中方案则是API的用户,如果无须深入了解实现细节,那么只需面对当前所遇到的复杂性即可。
WebDriver的开发人员更倾向于发现并在少数地方隔离这些复杂性,而不是传播它。这么做的原因之一是为用户着想。看看bug列表会知道,他们特别善于发现问题和缺陷,但是因为许多用户不是开发人员,复杂的API不会受欢迎。开发人员试图让API正确地引导大家。例如,考虑下面来自早期Selenium API的方法,每一个都用于设置输入元素的值:
• type
• typeKeys
• typeKeysNative
• keydown
• keypress
• keyup
• keydownNative
• keypressNative
• keyupNative
• attachFile
下面是WebDriver API中的等价方法:
• sendKeys
如前所述,这凸显了RC和WebDriver之间的主要思想差异——WebDriver在努力模拟用户,而RC在较低层次提供的API让用户难以或者无法使用。typeKeys和typeKeysNative之间的区别在于前者总是使用合成事件(synthetic event),而后者则尝试利用AWT Robot输入键值。令人失望的是,AWT Robot发送按键事件给具有焦点的任意窗口,也是说可能不是浏览器。相比之下,WebDriver的原生事件,直接把事件发送给窗口处理函数,避免了浏览器窗口必须具有焦点的要求。