加速 Selenium 测试执行最佳实践
Selenium 测试自动化的主要目的是加快测试过程。在大多数情况下,使用 Selenium 的自动化测试比手动测试执行得特别好。在实际自动化测试实践中,我们有很多方式可以加速 Selenium 用例的执行。
我们可以选择使用不同类型的等待、不同类型的 Web 定位器、不同的浏览器首选项,做出最明智的选择可以帮助加快 Selenium 测试的速度。在寻求加速 Selenium 测试时,还应该考虑优化 Selenium 测试基础架构,因为这可以显着提高测试执行速度。
在本文中,我主要从速度和性能的角度介绍 Selenium Web 测试最佳实践,帮助你能够更好地加速 Selenium 测试以获得更快的测试结果。
加速 Selenium 测试的最佳实践
随着产品的重大更新,维护和升级 Selenium 测试的过程开始变得过于复杂。与其限制 Selenium 测试性能,还不如从一开始就加速 Selenium 测试。
无论测试中的场景如何,以下是 Selenium 测试应该执行的操作:
使用本地 Selenium WebDriver 或远程 Selenium WebDriver 打开被测 URL 。
使用最合适的 Web Selenium 定位器(即 XPath、CssSelector、Linktext 等)定位所需的 WebElement 。
对定位的 WebElement 执行必要的操作。在被测页面上进行断言。
释放 WebDriver 使用的资源。
下面将介绍一些加速 Selenium 测试用例执行的 Selenium Web 测试最佳实践:
选择合适的网络定位器
Selenium 中的 Web 定位器被认为是任何测试场景的基本构建块。为了自动化与任何 Web 元素的交互,首先,我们使用合适的 Web 定位器定位 WebElement,然后对元素执行适当的操作。
以下是 Selenium 中一些广泛使用的 Web 定位器(排名不分先后):
XPath
CSS Selector
Name
LinkText
Partial LinkText
TagName
ClassName
问题是“哪个网络定位器在 Selenium 中定位元素最快?”。
就定位 WebElements 的速度而言,ID 是最快的 Web 定位器,因为 Selenium WebDriver 中的 ID 定位器对于页面上的每个元素都是唯一的。ID 定位器返回与指定值(或字符串)匹配的 WebElement。如果页面上存在多个具有相同 ID 的元素,则document.getElementById()
返回第一个匹配的元素。主流的 Web 浏览器优化了document.getElementById()
方法,从而帮助以更快的速度从 DOM 提供 WebElement。
如果 WebElement 没有 ID 属性,建议使用 name
属性。如果 WebElement 既没有 ID 也没有 name
属性,应该使用 CSS Selector Web Locator。CSS 引擎在所有主要浏览器中都是一致的,并且它们的性能经过调整,以通过 Selenium 中的 CSS 选择器获得更好的性能。
这也意味着您在使用此特定 Web 定位器时会遇到较少的浏览器兼容性问题。CSS Selector 提供更快的元素识别和减少的测试执行时间。此外,CSS Selector 最适合像 Internet Explorer 这样的退役浏览器,并且与 XPath 相比还提供更好的可读性。
XPath 是最慢的 Web 定位器,从一个浏览器移动到另一个浏览器时,您可能会遇到 XPath 一致性问题。仅当您无法选择在 Selenium WebDriver 中使用其他可靠的 Web 定位器时,才使用 XPath 来定位 Web 元素。
下面列出了按执行速度升序排列的 Web 定位器:
ID
Name
CSS Selector
XPath
使用更少的网络定位器
如果你已经选择了最适合加速 Selenium 测试的 Web 定位器,下一步应该是将定位器的数量保持在最低限度。
每次使用 find_element(By)
或 find_elements(By)
方法来定位所需的 Web 元素时,都会执行对 DOM 树的访问。访问 DOM 树的次数越多,Selenium 脚本的执行时间就越长。使用较少的 Web 定位器是 Selenium Web 测试的最佳实践之一,尤其是把 Selenium 脚本的最佳执行速度为目标时。这种做法还提高了测试脚本的可读性,从而最大限度地减少了维护脚本的时间。
避免 Thread.sleep()
网站或 Web 应用程序可以包含本质上是静态或动态的内容。现代网站使用 AJAX(异步 JavaScript 和 XML)在网页上动态加载内容。因此,页面上的 WebElements 可能会以不同的时间间隔加载,从而在对尚未在 DOM 中的元素执行操作时造成困难。
建议通过监控 document.readyState
的状态来检查 DOM 状态。当 document.readyState
完成时,意味着页面上的所有资源都已加载。现在可以对页面上的 WebElements 进行相关操作。测试代码中的等待(几秒钟)还增加了加载页面资源所需的必要延迟。
尽管在 Selenium 中有多种添加等待的方法,但必须不惜一切代价避免使用 Thread.sleep(sleep_in_miliseconds)
。Selenium 中的 Thread.sleep()
方法将代码执行暂停指定的时间。
在上面的代码片段中,我们添加了 5 秒的等待。如果页面元素在指定的持续时间(例如,2 秒)内加载良好怎么办?在这种情况下,等待 3 秒会不必要地增加测试执行时间。由于页面加载时间取决于各种外部参数(即服务器负载、页面设计、缓存、网络带宽等),因此无法预测页面的加载时间。在执行自动化浏览器测试时,在 Selenium 中测量页面加载时间是一个很好的做法。
建议避免使用 Thread.sleep()
来加速 Selenium 测试,因为无论网页状态如何,该方法都会执行睡眠(持续固定的时间)。
复用浏览器实例
所有可与 Selenium 一起使用的测试自动化框架都提供了用于加速测试开发和执行的注解。注释还有助于使用不同的输入值执行测试。但是,根据测试要求使用正确的注释集可以加快 Selenium 测试的速度。
以下是流行的测试自动化框架的一些广泛使用的注释:
在某些情况下,你可能希望在同一浏览器和操作系统组合上运行单个测试(或一组测试)。在这种情况下,在每个测试开始时创建 Selenium WebDriver 的新实例会增加测试执行的额外开销。
用于 Selenium 的 JUnit
以下是 JUnit for Selenium 中注解的执行顺序:
Junit 执行顺序
在使用 JUnit 框架的 Selenium 自动化测试中,Selenium WebDriver 实例是在 @Before 注释下实现的 SetUp 方法中创建的。创建的实例在 @After 注解下实现的 TearDown 方法中销毁。
Selenium 的 TestNG
下面是 TestNG for Selenium 中注解的执行顺序:
TestNG 执行顺序
同理,对于 Selenium 中的 TestNG 测试,SetUp 方法在 @BeforeMethod 注解下实现,TearDown 方法在 @AfterMethod 注解下实现。
使用显式等待
Selenium 中的隐式等待应用于测试脚本中的所有 Web 元素。Selenium 中的显式等待允许对页面上存在的 WebElements 执行条件等待。例如,如果指定的 WebElement 在显式等待中提到的持续时间内可见,则抛出 ElementNotVisibleException。如果定位的元素是可点击的,则 elementToBeClickable 方法返回一个 WebElement。
WebDriverWait
和 ExpectedConditions
类的组合用于对 WebElements 执行显式等待。Explicit Wait 的好处是运行在代码上,而不是远程 Selenium 部分。显式等待不会等到持续时间结束,而是等待指定条件一满足就退出。如果条件找到 WebElement,则返回该元素作为结果。如果 WebElement 不存在于 DOM 中,即使条件中指定的持续时间已过,也会引发 TimeoutException。
在下面显示的代码段中,对 visibilityOfElementLocated 条件执行了 5 秒的显式等待。如果 ID = 'element' 的 WebElement 在 5 秒内找到,则显式等待退出,并返回所需的 WebElement。
显式等待的测试脚本性能更好,因为一旦找到元素就可以访问 WebElement。显式等待加速 Selenium 测试,因为等待并非“总是”在整个等待持续时间内执行。
创建原子和自主测试脚本
这是编写高效 Selenium 测试的最基本要求。无论测试场景的复杂程度如何,都必须将复杂场景分解为多个“独立且原子”的测试用例。
像 TestNG 这样的测试自动化框架支持通过诸如 dependsOnMethods(对于方法)和 dependsOnGroups(对于组)之类的注释来声明测试方法之间的显式依赖关系。如果你希望在测试方法之间共享数据和状态时,应只在 Selenium 测试脚本中使用测试依赖项。
另一方面,原子测试可用于检测故障。保持测试的简短和原子性还有助于减少用于维护测试的工作量。
在 Selenium 测试中具有原子性可以最大程度地减少测试依赖性,有助于隔离测试实施中的问题,减少维护工作并加快 Selenium 测试的速度。
并行测试
Selenium 中的并行测试允许您在不同的测试环境中同时运行相同的测试。如果您计划使用内部 Selenium Grid 进行分布式测试,建议利用 Selenium Grid 4 提供的功能来加速测试场景的执行。
Selenium 并行测试在软件测试中有许多好处,以下是其中的一些主要优势:
提高测试效率:通过并行测试,可以同时运行多个测试用例,充分利用多核处理器和资源,显著提高测试的执行速度。相比串行测试,可以更快地获得测试结果,加快反馈周期,提高团队的工作效率。
加速持续集成:在持续集成和持续交付流程中,测试是关键环节。通过并行测试,可以快速运行大量的测试用例,及时发现和解决问题,确保软件的质量和稳定性,加快交付速度。
提高测试覆盖率:并行测试能够更快地执行大量的测试用例,从而提高测试覆盖率。测试覆盖率越高,发现问题的可能性就越大,软件的质量也会得到提升。
更好地模拟真实环境:并行测试可以模拟真实的多用户、高负载场景,更真实地反映系统在生产环境中的表现。这有助于发现潜在的性能问题和瓶颈,提前做出优化和调整。
发现潜在问题:并行测试能够同时运行多个测试用例,从而发现一些在串行测试中不容易暴露的问题。例如,可能会发现在特定并发条件下的竞争条件和资源冲突问题。
提高自动化测试的价值:并行测试尤其适用于自动化测试。通过并行执行自动化测试用例,可以快速运行大量测试,为团队提供实时反馈,帮助团队快速发现和解决问题。
优化硬件资源利用率:在并行测试中,可以将测试用例分布到多台测试机或浏览器上,充分利用硬件资源,提高测试执行的效率。
快速发现问题:通过并行测试,可以同时运行多个测试用例,从而快速发现潜在的问题和缺陷。这样可以及早解决问题,避免问题扩散和影响其他测试用例的执行。
综上所述,Selenium 并行测试在软件测试中具有重要的优势,可以提高测试效率,加速持续集成,提高测试覆盖率,发现潜在问题,优化硬件资源利用率等。因此,在进行 Selenium 自动化测试时,考虑并实现并行测试是非常值得推荐的做法。
禁用图像
一旦创建了 Selenium WebDriver 的实例,Selenium 中的 driver.get() 方法用于打开被测页面。网页的加载很大程度上取决于页面的组成。如果页面上有大量图像,页面加载时间会增加。
根据测试需求,您可以禁用图片加载,从而加快网页加载速度。使用特定于浏览器的设置,您可以禁止在相应的 Web 浏览器中加载图像。
这是在 Chrome 中禁用图像加载以加快 Selenium 测试的实现:
从上面的实现中可以看出,我们禁用了图片加载,这大大缩短了该电子商务网站的页面加载时间。
这是在 Firefox 中禁用图像加载以加快 Selenium 测试的实现:
在上面的实现中,我们通过将 Firefox 首选项 permissions.default.image 设置为 2 来禁用加载图像。禁用图像加载是应该使用的被破坏的 Selenium Web 测试最佳实践之一,尤其是当被测页面上有许多图像。
使用 Headless
运行 Selenium 自动化测试的目的是检查以验证与底层 UI 元素的交互。在这种情况下,您可能希望通过在非无头模式下调用浏览器驱动程序来验证交互。
无头浏览器允许您在没有浏览器 GUI 或任何其他 GUI 的情况下运行浏览器 UI 测试。由于跨浏览器测试在后端运行,无头测试增强了跨浏览器测试的性能。流行的浏览器,如 Chrome、Firefox 等,可以在无头模式下运行。基于云的实践中,设置为在无头模式下运行所需的浏览器功能如下所示。
Headless 浏览器测试是 Selenium Web 测试最佳实践之一,当您不打算检查通过测试脚本和相应的浏览器驱动程序实现的 UI 交互时,应该使用它。没有浏览器 UI 和无头浏览器的各种 UI 可以加速 Selenium 测试。
一些流行的无头浏览器(或驱动程序)形式是:
HtmlUnit
Splash
PhantomJS
TrifleJS
ZombieJS
SimpleBrowser
具体实践这里不一一赘述,感兴趣的同学可以自行去官方查看 Demo。
版权声明: 本文为 InfoQ 作者【FunTester】的原创文章。
原文链接:【http://xie.infoq.cn/article/cd61ba859546fca3d65c94302】。文章转载请联系作者。
评论