36

我将编写一堆浏览器扩展(每个流行的浏览器都具有相同的功能)。我希望,一些代码将被共享,但我还不确定这一点。当然,一些扩展将使用本机 API。我在 TDD/BDD 方面没有太多经验,我认为现在是从这个项目中开始遵循这些想法的好时机。

问题是,我不知道如何处理它。我应该为每个浏览器编写不同的测试吗?这些测试我应该走多远?这些扩展将非常简单——本地存储中的一些数据、刷新页面和通过 Web 套接字进行侦听。

我观察到为什么对我来说很难——因为有很多行为,而不是太多模型,它们也依赖于平台。

4

2 回答 2

73

我练习了两种不同的方法来测试我的浏览器扩展:

  • 单元测试
  • 集成测试

介绍

在整个答案中,我将使用 Rob W 扩展的跨浏览器YouTube 歌词作为示例。此扩展的核心是用 JavaScript 编写的,并使用 AMD 模块进行组织。构建脚本会为每个浏览器生成扩展文件。使用r.js,我简化了浏览器特定模块的包含,例如用于跨域 HTTP 请求和持久存储(用于首选项)的模块,以及用于 IE 的具有大量 polyfill 的模块。

该扩展插入一个面板,其中包含当前在 YouTube、Grooveshark 和 Spotify 上播放的歌曲的歌词。我无法控制这些第三方网站,因此我需要一种自动化的方式来验证扩展程序是否仍能正常工作。

工作流程

开发过程中:

  1. 实现/编辑功能,如果该功能不是微不足道的,则编写单元测试。
  2. 运行所有单元测试以查看是否有任何问题。如果有任何问题,请返回 1。
  3. 提交给 git。

发布前:

  1. 运行所有单元测试以验证各个模块是否仍在工作。
  2. 运行所有集成测试以验证整个扩展是否仍在工作。
  3. 凹凸版本,构建扩展。
  4. 将更新上传到官方扩展库和我的网站(Safari 和 IE 扩展必须由您自己托管)并提交到 git。

单元测试

我使用mocha + expect.js编写测试。我不会测试每个模块的所有方法,只测试重要的方法。例如:

  • DOM 解析方法。大多数 DOM 解析方法(包括 jQuery)都存在缺陷:加载任何外部资源并执行 JavaScript。
    我验证 DOM 解析方法是否正确解析 DOM 而没有负面影响。

  • 首选项模块:我验证数据可以保存和返回。

  • 我的扩展从外部来源获取歌词。这些源在单独的模块中定义。这些定义被模块识别和使用,该InfoProvider模块接受查询(黑框)并输出搜索结果。

    • 首先我测试InfoProvider模块是否正常工作。
    • 然后,对于 17 个源中的每一个,我将预定义的查询传递给源(使用InfoProvider)并验证结果是否符合预期:
      • 查询成功
      • 返回的歌曲标题匹配(通过应用单词相似度算法)
      • 返回的歌词长度在预期范围内。
  • UI 是否没有明显损坏,例如通过单击关闭按钮。

这些测试可以直接从本地服务器运行,也可以在浏览器扩展中运行。本地服务器的优点是您可以编辑测试并刷新浏览器以查看结果。如果所有这些测试都通过了,我会从浏览器扩展运行测试。
通过向我的构建脚本传递一个额外的参数debug,单元测试与我的扩展捆绑在一起。

在网页中运行测试是不够的,因为扩展的环境可能与普通页面不同。例如,在 Opera 12 扩展中,没有全局location对象。

备注:我没有在发布版本中包含测试。大多数用户不会努力报告和调查错误,他们只会给出低评价并说“不起作用”之类的话。在发布之前确保您的扩展功能没有明显的错误。

概括

  • 将模块视为黑盒。你不在乎里面有什么,只要输出匹配是预期的或给定的输入。
  • 从测试扩展的关键部分开始。
  • 确保测试可以轻松构建和运行,可能在非扩展环境中。
  • 不要忘记在扩展的执行上下文中运行测试,以确保在扩展的上下文中没有约束或意外条件会破坏您的代码。

集成测试

我使用 Selenium 2 来测试我的扩展程序是否仍然适用于 YouTube、Grooveshark (3x) 和 Spotify。

最初,我只是使用Selenium IDE来记录测试并查看它是否有效。一切顺利,直到我需要更大的灵活性:我想根据测试帐户是否登录有条件地运行测试。这对于默认的 Selenium IDE 是不可能的(据说使用FlowControl 插件是可能的——我没有尝试过)。

Selenium IDE 提供了以其他格式导出现有测试的选项,包括 JUnit 4 测试 (Java)。不幸的是,这个结果并不令人满意。许多命令无法识别。

所以,我放弃了 Selenium IDE,转而使用 Selenium。
请注意,当您搜索“Selenium”时,您会找到有关 Selenium RC (Selenium 1) 和 Selenium WebDriver (Selenium 2) 的信息。第一个是旧的和已弃用的,后者(Selenium WebDriver)应该用于新项目。

一旦你了解了文档的工作原理,它就很容易使用。
我更喜欢项目页面上的文档,因为它通常简洁(wiki)和完整(Java docs)。

如果您想快速入门,请阅读入门 wiki 页面。如果您有空闲时间,请查看SeleniumHQ 的文档,尤其是Selenium WebDriverWebDriver:高级用法
Selenium Grid也值得一读。此功能允许您在不同的(虚拟)机器上分发测试。如果您想同时在 IE8、9 和 10 中测试您的扩展,那就太好了(要运行多个版本的 Internet Explorer,您需要虚拟化)。

自动化测试很好。还有什么好看的?自动安装扩展!
ChromeDriver和FirefoxDriver支持安装扩展,如本例所示

对于SafariDriver,我编写了两个类来安装自定义 Safari 扩展。我已经发布了它并在 PR 中发送给 Selenium,因此将来可能对所有人都可用:https ://github.com/SeleniumHQ/selenium/pull/87

OperaDriver不支持安装自定义扩展(从技术上讲,它应该是可能的)
请注意,随着基于Chromium 的 Opera的出现,旧的 OperaDriver 不再工作。

有一个Internet Explorer 驱动程序,这个绝对不允许安装自定义扩展。Internet Explorer 没有对扩展的内置支持。扩展是通过 MSI 或 EXE 安装程序安装的,它们甚至没有集成在 Internet Explorer 中。因此,为了在 IE 中自动安装您的扩展程序,您需要能够静默运行安装 IE 插件的安装程序。我还没试过这个

于 2013-06-28T17:35:29.707 回答
4

测试浏览器扩展也给我带来了一些困难,但我已经决定在几个不同的领域实现测试,我可以从 Selenium 驱动的浏览器同时调用这些测试。

我使用的步骤是:

首先,我编写集成到扩展代码中的测试代码,只需转到特定 URL 即可激活。当扩展程序看到该 URL 时,它开始运行测试。

然后,在激活扩展中的测试的页面中,我执行服务器端测试以确保 API 执行,并在那里记录和记录问题。我记录了调用的方法、它们花费的时间以及任何错误。所以我可以看到扩展调用的方法、Web 性能、业务逻辑性能和数据库性能。

最后,我使用 Selenium 自动调用浏览器指向该特定 URL,并在任何给定客户端系统上记录它们的性能以及其他测试信息、错误等:

http://docs.seleniumhq.org/

通过这种方式,我可以根据浏览器、扩展程序、服务器、应用程序和数据库来分解测试,并根据特定的测试集将它们链接在一起。将它们放在一起需要一些工作,但是一旦完成,您就可以拥有一个非常好的扩展测试框架。

通常用于跨浏览器扩展开发以维护单个代码库,我使用 crossrider,但您可以使用任何框架或使用本机扩展来执行此操作,Selenium 不在乎,它只是将扩展驱动到一个特定页面并允许您进行交互和执行测试。

这种方法的一个好处是您也可以将它用于实时用户。如果您正在为您的扩展提供支持,请让用户访问您的测试 url,您将立即看到扩展和服务器端性能。当然,您不会获得 Selenium 测试,但您会以这种方式捕获很多问题 - 当您针对各种浏览器和浏览器版本进行编码时非常有用。

于 2013-06-26T19:57:41.050 回答