原子化:为什么?
分类
这是我撰写的关于 Selenium WebDriver 内部机制的技术文章系列的第一篇。如果您对技术细节不感兴趣,现在可以离开了。
还在?太棒了。
让我们回到 Selenium 和 WebDriver 项目合并之前。很明显,当时存在两个独立的代码库。更仔细地观察,从稍微不同的角度来看,存在的代码库不止两个。我们使用 WebDriver 的测试套件来定义多个、基本独立的驱动程序代码库的行为。 IE 驱动程序使用 C 语言编写,HtmlUnit 驱动程序使用 Java 编写,而 Firefox 驱动程序主要使用 Javascript 编写,等等。
这意味着存在大量的“一致代码”:执行相同功能,但以不同方式实现的代码。这自然会导致驱动程序之间的行为可能出现分歧。更糟糕的是,这意味着当发现错误时,我们必须在每个浏览器中检查它,并且无法确定个人是否能够实际修复代码。毕竟,并非每个人都熟悉我们项目中使用所有语言的编写,或者熟悉所有技术。对于像 Selenium 这样的开源项目,这是一个主要问题:我们依赖于相对较小的核心开发人员团队,并由更大的个人团队提供小的更改和修复。任何使我们难以作为开发社区有效运作的事情都是不好的。
因此,我们想要一种摆脱困境的方法;一种机制,可以方便地在各种驱动程序和 Selenium 核心之间共享代码,允许我们仅在一个地方修复错误,并使该修复传播到使用此机制的每个驱动程序。更重要的是,它必须易于使用,并且对于不熟悉多种语言和技术的人来说,可以快速入门。
这个机制会是什么样的呢?好吧,有几个因素会影响到这一点,但最重要的一点是,我们考虑合并的大部分代码都在查询浏览器的状态(“查找元素”、“获取此属性的值”),正如 Jason Huggins 随时会向我指出的那样,查询浏览器状态的自然语言是 Javascript。Javascript 的一个优点是,它可以实现快速的开发周期。只需修改测试,保存,然后在浏览器中点击“刷新”即可。这很有吸引力。更好的是,有很多开发人员熟悉 Javascript。
因此,我们决定使用 Javascript。
因为这个共享代码将由浏览器自动化所需的最有用的小功能片段组成,我们决定将其称为“浏览器自动化原子”,简称“原子”。与其从头开始编写它们,最简单的方法是从现有代码中提取它们 — 这些代码已经过实战测试,所以我们知道它们是健壮的。
有一个非常明显的缺陷:并非每个驱动程序都使用 Javascript 编写。虽然我们在每个浏览器中都有可用的机制 (http://selenium.googlecode.com/svn/trunk/docs/api/java/org/openqa/selenium/JavascriptExecutor.html
) 来执行 JS,但是如果您想查询 DOM,将大量代码转储到浏览器的 JS 引擎上是极其低效的。毕竟,大多数代码都是不需要的,而且并非所有 JS 引擎都是相同的。有些引擎速度非常快。其他的则不然。
将代码分解成易于管理的大小合适的模块而不是放在单个庞大的文件中也很好,这意味着需要一些巧妙的“模块加载”功能。除非这段代码并非总是要在可以编写“script”标签来加载其他脚本的环境中执行。您无法在 Firefox 扩展的内部执行此操作,尽管您可以通过其他方式加载文件。无论我们如何将模块连接在一起,都需要能够应对这种情况。
啊!这些相互冲突的要求:包含我们要使用的函数的小模块,没有多余的代码,以及为了尽量减少加载额外模块的麻烦,所有内容都放在一个文件中。这听起来不像是一个非常兼容的列表。我们如何解决这些差异是我下一篇文章的主题….