前不久,InfoQ向大家推荐了几本有关软件架构的新书,引起了国内读者的广泛兴趣。其中一本是《开源应用架构(The Architecture of Open Source Applications)》, 来自知名开源项目的各位作者对软件的设计进行了说明。通过对这些成功的系统架构进行概览,让软件工程师可以彻底了解佳实践和陷阱。InfoQ中文站响应 读者的需求,整理了该书有关知名开源软件架构的精彩内容,供国内开发社区借鉴。本期介绍的是浏览器自动化工具Selenium WebDriver的软件架构,第一部分主要分享了Selenium WebDriver的演变历史和架构观点。
Selenium是一个浏览器自动化工具,通常用来编写Web应用 的端到端测试。浏览器自动化工具准确执行你所期望的行为:自动化浏览器的某个控件,从而可以自动重复执行任务。这听起来像是一个很容易解决的问题,但是 正如我们即将看到的那样,其实Selenium成功的背后凝聚了大量的工作。
介绍Selenium WebDriver软件架构的技术专家是来自Google的Simon Stewart,他是Selenium的核心贡献者和Selenium WebDriver的创建者。
Simon Stewart首先谈起了Selenium的组成部分:
在介绍Selenium架构之前,好先了解一下该项目的各个相关组成部分是如何结合在一起的。从较高的层次看,Selenium由三种工具组成。 第一个工具Selenium IDE,是Firefox的扩展插件,支持用户录制和回访测试。录制/回访模式存在局限性,对许多用户来说并不适合,因此第二个工具—— Selenium WebDriver提供了各种语言环境的API来支持更多控制权和编写符合标准软件开发实践的应用程序。后一个工具——Selenium Grid帮助工程师使用Selenium API控制分布在一系列机器上的浏览器实例,支持并发运行更多测试。在项目内部,它们分别被称为“IDE”、“WebDriver”和“Grid”。
追根溯源,Selenium和WebDriver初是两个独立的项目,Simon Stewart解释了发展的历史:
Jason Huggins在2004年发起了Selenium项目,当时他在ThoughtWorks公司开发内部的时间和费用(Time and Expenses)系统,该应用使用了大量的JavaScript。虽然Internet Explorer在当时是主流浏览器,但是ThoughtWorks还使用一些其他浏览器(特别是Mozilla系列),当员工在自己的浏览器中无法正常 运行T&E系统时会提交bug报告。当时的开源测试工具要么关注单一浏览器(通常是IE),要么是模拟浏览器(如HttpUnit)。购买商业 工具授权的成本会耗尽这个小型内部项目的有限预算,所以它们都不是可行的测试选项。
在自动化困难的情况下,通常会依靠手动测试。当开发团队规模很小或者构建发布非常频繁时,这种方式不太适用。同时,让人手动执行原本可以自动化的脚本也是一种对人力的浪费。沉闷重复的任务越无聊,人们工作会越慢而且比机器犯更多错误。手动测试也不是一种选择。
幸运的是,所有被测试的浏览器都支持Javascript。Jason和他所在的团队有理由采用Javascript编写一种测试工具来验证应用的行为。他们受到FIT(Framework for Integrated Test) 的启发,使用基于表格的语法替代了原始的Javascript,这种做法支持那些编程经验有限的人在HTML文件中使用关键字驱动的方式来编写测试。该 工具,初称为“Selenium”,后来称为“Selenium Core”,在2004年基于Apache 2授权发布。
Selenium的表格格式类似于FIT的ActionFixture。表格的每一行分为三列。第一列给出了要执行的命令名称,第二列通常包含元 素标记符,第三列包含一个可选值。例如,如下格式表示了如何在名称为“q”的元素中输入字符串“Selenium WebDriver”:
type name=q Selenium WebDriver
因为Selenium过去使用纯JavaScript编写,它的初设计要求开发人员把准备测试的应用和Selenium Core、测试脚本部署到同一台服务器上以避免触犯浏览器的安全规则和JavaScript沙箱策略。在实际开发中,这种要求并不总是可行。更糟的是, 虽然开发人员的IDE能够帮助他们快速处理代码和浏览庞大的代码库,但是没有针对HTML的相关工具。人们很快意识到维护一个中等规模的测试集是笨拙而 痛苦的过程。
为了解决这个问题和其他问题,我们编写了HTTP代理,这样所有的HTTP请求都会被Selenium截获。使用代理可以绕过“同源”规则(浏览器 不支持Javascript调用任何当前页面所在服务器以外的其他任何东西)的许多限制,从而缓解了首要弱点。这种设计使得采用多种语言编写 Selenium绑定成为可能:它们只需把HTTP请求发送到特定URL。连接方法基于Selenium Core的表格语法严格建模,称之为“Selenese”。因为语言绑定在远程控制浏览器,所以该工具称为“Selenium Remote Control”或者“Selenium RC”。
在Selenium处于开发阶段的同时,另一款浏览器自动化框架WebDriver也正在ThoughtWorks公司的酝酿之中。 WebDriver的初代码在2007年初发布。WebDriver项目的初衷是把端对端测试与底层测试工具隔离开。通常情况下,这种隔离手段通过适配 器(Adapter)模式完成。WebDriver正是来源于该方法在许多项目上的不断实践应用,初是HtmlUnit的封装,工具发布后很快开始支持 Internet Explorer和Firefox。
在WebDriver初发布时,与Selenium RC存在显著差异,尽管它们都属于浏览器自动化的API工具。对于用户来说,明显的区别在于Selenium RC提供基于字典的API,所有方法都在一个类中开放,而WebDriver的API更面向对象。此外,WebDriver仅支持Java,而 Selenium RC提供广泛的语言支持。技术差异也很明显:Selenium Core(RC的基础)基本上是JavaScript应用,运行在浏览器的安全沙箱之内。WebDriver则尝试原生绑定到浏览器中,绕开了浏览器的安 全模型,代价是框架自身的开发投入显著增加。