改进跨浏览器测试,第1部分:当今的Web应用程序测试

2020-12-19 06:49:03

测试Web应用程序可能是一个挑战。与大多数其他类型的软件不同,它们可以跨多种平台和设备运行。无论外形尺寸或浏览器选择如何,它们都必须坚固耐用。

我们知道这是开发人员所感到的问题:当MDN开发人员需求评估要求网络开发人员提供其主要痛点时,跨浏览器测试在2019年和2020年均位居前五名。

对2020年结果的分析显示了一个小组,由13%的受访者组成,对于他们而言,编写和运行测试的困难是他们使用Web平台的总体最大痛苦点。

在Mozilla,我们将其视为号召性用语。致力于构建更好的Internet,我们希望为Web开发人员提供构建良好的Web体验所需的工具-包括出色的测试工具。

在本系列文章中,我们将探索当前的Web应用程序测试环境,并解释Firefox当前正在做什么,以允许开发人员在Firefox中运行更多类型的测试。

当前大多数跨浏览器测试自动化都使用WebDriver,这是W3C用于浏览器自动化的规范。 WebDriver使用的协议起源于Selenium,Selenium是最古老,最受欢迎的浏览器自动化工具之一。

要了解WebDriver的功能和局限性,让我们深入研究一下它的幕后工作原理。

WebDriver提供了基于HTTP的同步命令/响应协议。在此模型中,诸如Selenium之类的客户端(在WebDriver中被称为本地端)使用一组固定的步骤与远程HTTP服务器进行通信:

本地端向远端发送代表WebDriver命令的HTTP请求。

远端遵循WebDriver规范的要求,采取特定于实现的步骤来执行命令。

该远程端HTTP服务器可以内置在浏览器中,但是最常见的设置是所有HTTP处理都在特定于浏览器的驱动程序二进制文件中进行。这将接受WebDriver HTTP请求并将其转换为内部格式以供浏览器使用。

例如,在自动化Firefox时,geckodriver将WebDriver消息转换为Gecko的自定义木偶协议,反之亦然。 ChromeDriver和SafariDriver以类似的方式工作,每种都使用特定于其关联浏览器的内部协议。

为了更好地理解这一点,让我们举一个简单的示例:导航到页面,查找元素并测试该元素上的属性。从测试作者的角度来看,实现此目的的代码可能如下所示:

此示例中的每一行代码均导致从本地端到远程端的单个HTTP请求,代表单个WebDriver命令。

直到远端接收到相应的HTTP响应,程序才继续运行。例如,在最初的browser.go调用中,仅当浏览器完成了请求页面的加载后,远端才会发送响应。

该程序在线生成以下HTTP流量(为简便起见,省略了一些不重要的细节):

此时,浏览器将执行网络操作以导航到请求的URL http:// localhost:8000 / index.html。该页面完成加载后,远程端将以下响应发送回自动化客户端。

即使代码的三行代码都涉及大量的网络操作,控制流仍易于理解,并易于以各种通用编程语言表示。这与浏览器内部的情况大不相同,在浏览器内部,一个看起来很简单的操作(例如加载页面)具有大量异步步骤。

远程端处理所有这些复杂性的事实使编写自动化客户端变得更加容易。

在上面的简单模型中,本地端直接与受浏览器控制的驱动程序二进制文件对话。但是在实际的测试部署方案中,情况可能会更加复杂。可以在本地端和驱动程序之间部署任意HTTP中间件。

一种常见的应用是提供配置功能。使用诸如Selenium Grid之类的中介,单个WebDriver HTTP端点可以处理大量的操作系统和浏览器组合,并将每个测试的命令代理到所请求的计算机。

HTTP的易于理解的语义,再加上大量现有工具,使得这种设置相对易于大规模构建和部署,即使是在不受信任的,可能具有高延迟的网络(如Internet)上也是如此。

这对于SauceLabs和BrowserStack等在远程服务器上运行自动化的服务非常重要。

HTTP的同步命令/响应模型对WebDriver施加了一些限制。由于浏览器只能响应命令,因此很难对特定请求上下文之外的浏览器中可能发生的事情进行建模。

一个明显的例子是警报。警报可以随时显示,因此每个WebDriver命令都必须在运行前专门检查警报是否存在。

日志记录也会出现类似问题。理想的API会在日志事件生成后立即发送,但是对于基于HTTP的WebDriver,这是不可能的。相反,日志记录API需要在浏览器端进行缓冲,并且客户端必须接受它可能不会收到所有日志消息的信息。

对标准化不良,不可靠的API的担忧意味着,尽管有一个常见的用户请求,但日志记录功能尚未将其纳入WebDriver的W3C规范中。

尽管存在这些限制,WebDriver仍采用HTTP模型的原因之一是编程模型的简单性。借助完全阻塞的API,仅使用2000年代早期的主流语言功能就可以轻松编写WebDriver客户端。

从那时起,许多编程语言都获得了对处理事件和异步控制流的一流支持。这意味着原始WebDriver协议中包含的一些基本假设(例如异步,事件驱动的代码难以编写)不再适用。

除了通过WebDriver进行自动化之外,现代的浏览器还提供远程访问,以使用浏览器的DevTools。对于难以在运行页面本身的同一台计算机上调试问题(例如仅在移动设备上发生的问题)的情况,这是至关重要的。

不同的浏览器提供不同的DevTools功能,这些功能通常需要引擎的显式支持,并公开Web内容不可见的实现细节。因此,每个浏览器引擎根据其特定要求具有唯一的DevTools协议就不足为奇了。

在DevTools中,有一个核心要求,即UI必须响应浏览器引擎发出的事件。示例包括记录控制台消息和网络请求的出现,以便用户可以跟踪进度。

这意味着DevTools协议不使用HTTP的命令/响应范例。而是使用双向协议,其中消息可能来自客户端或浏览器。这样,DevTools可以实时更新,以响应浏览器中发生的更改。

远程自动化并不是DevTools的核心用例。在一种情况下很常见的某些操作在另一种情况下很少见。例如,几乎所有自动化测试中都存在客户端启动的导航,但是在DevTools中很少出现。

不过,调试时需要进行低级控制,这意味着可以在DevTools协议功能集的顶部编写许多自动化功能。实际上,在某些浏览器(例如Chrome)中,用于弥合WebDriver二进制文件和浏览器本身之间差距的浏览器内部消息格式实际上是DevTools协议。

这不可避免地引发了一个问题,即是否有可能直接在DevTools协议之上构建自动化。随着语言为异步控制流提供更好的支持,现代Web应用程序要求对测试进行更底层的控制,诸如Google Puppeteer之类的库采用了DevTools协议,并在顶部构建了特定于自动化的客户端库。

这些库支持高级功能,例如网络请求拦截,这些功能很难在基于HTTP的WebDriver之上构建。通常基于承诺的API也更像是现代的前端编程,这使这些工具在Web开发人员中很受欢迎。

甚至主要是基于WebDriver的工具都添加了其他功能,这些功能无法仅通过WebDriver来实现。例如,Selenium 4中的一些新功能,例如访问控制台日志和更好地支持HTTP身份验证,都需要双向通信,并且最初仅在能够使用Chrome的DevTools协议的浏览器中受支持。

尽管使用DevTools进行自动化在功能集方面颇具吸引力,但也充满了问题。

DevTools协议是特定于浏览器的,并且可以暴露很多不属于Web平台的内部状态。这意味着使用DevTools功能实现自动化的库通常绑定到特定的渲染引擎。

他们还注视着这些引擎的变化。与引擎内部的紧密耦合意味着DevTools协议通常只能提供非常有限的稳定性保证。

对于DevTools本身而言,这不是一个大问题;通常,同一团队拥有前端和后端,因此任何重构都必须同时更新客户端和服务器,并且跨版本兼容性不是一个严重的问题。但是对于自动化而言,这给客户端库开发人员和测试作者都带来了沉重的负担。

使用WebDriver,单个客户端可以与任何受支持的浏览器版本一起使用。使用基于DevTools的自动化,每个浏览器版本都可能需要一个新客户端。例如,Puppeteer就是这种情况,其中每个Puppeteer版本都与特定版本的Chromium绑定在一​​起。

DevTools协议是特定于浏览器的事实使得将它们用作跨浏览器工具的基础非常具有挑战性。赛普拉斯(Cypress)和微软的Playwright等一些自动化客户端在这里做出了英勇的努力,避开了WebDriver,但仍支持多种浏览器。

通过将现有的DevTools协议和通过底层浏览器代码的补丁程序或通过WebExtensions实现的自定义协议结合使用,它们在支持多个浏览器引擎的同时,提供了WebDriver无法实现的功能。

需要由自动化库维护的大量代码,并将该库置于浏览器引擎更新的平台上,这使维护变得困难,并且使库作者减少了专注于其核心自动化功能的时间。

正如我们所看到的,Web应用程序测试生态系统正变得支离破碎。大多数跨浏览器测试都使用WebDriver。所有主要浏览器引擎都支持的W3C规范。

但是,WebDriver基于HTTP的协议存在局限性,这意味着自动化库越来越多地选择使用特定于浏览器的DevTools协议来实现高级功能,而在此之前,跨浏览器支持就没有了。

测试作者不必在访问功能和特定于浏览器的工具之间进行选择。客户的作者也不应被迫跟上浏览器引擎开发的快速步伐。

在下一篇文章中,我们将介绍Mozilla为将以前仅Chromium的测试工具引入Firefox而进行的一些工作。 感谢TantekÇelik,Karl Dubost,Jan Odvarko,Devin Reams,Maire Reavy,Henrik Skupin和Mike Taylor的宝贵反馈和建议。