写点什么

你并不总希望在真正浏览器中进行测试:Selenium 来营救

  • 2019-01-15
  • 本文字数:4893 字

    阅读完需:约 16 分钟

你并不总希望在真正浏览器中进行测试:Selenium来营救

Selenium 是一个在 Web 浏览器中进行自动化测试的强大工具。虽然 Selenium Web 驱动程序支持所有主流的浏览器,但你并不总是希望在真正的浏览器中进行测试。

本文要点

  • Selenium 运行时没有 UI 界面;

  • 不再支持 PhantomJS;

  • JBrowser 驱动程序是一个支持 Java 8 的低开销选项;

  • 如果你需要 Java 11 支持,那么当前所有的 Java Selenium 驱动程序都需要安装一个真正的浏览器。


Selenium是一个在 Web 浏览器中进行自动化测试的强大工具。虽然 Selenium Web 驱动程序支持所有的主流浏览器,但你并不总是希望在真正的浏览器中进行测试。Selenium 来营救!本文中的示例来自GitHub库。所有示例都使用 JUnit 5 和 Maven 运行。每个示例都有 Java 11 和 Java 8 支持说明。

使用 Selenium 有什么好处?

Selenium 在运行时没有用户界面(UI)。使用 Selenium 进行测试的一大好处是性能——因为 Selenium 没有 UI,所以它们比真正的浏览器快。


一些 Selenium 还有另外一个优势——依赖。当在像 Jenkins 这样的持续集成服务器上进行测试时,机器可能没有安装真正的浏览器。根据你的环境,你可能没有权限安装一个。


另一方面,需要安装“真正的”浏览器的 Selenium 浏览器非常适合开发。例如,Chrome 和 Firefox 都可以在无头模式下运行。在调试 Selenium 脚本时,临时关闭无头模式并观看程序运行非常有用。这样你就可以直观地看到哪里出了问题。

HtmlUnitDriver——最初的 Selenium 驱动程序

过去,Selenium 带有一个内置的 Selenium 驱动程序 HtmlUnitDriver。虽然这个驱动程序仍然受支持,但它现在是一个单独的依赖项,并且不出所料地使用了 Html Unit 框架。在单页应用程序和主要基于 AJAX 的页面出现之前,这个驱动程序是一个非常好的选择。你可以选择是否运行页面 JavaScript,而且它在内存中运行并且非常快。对于包含大量 HTML 数据的 Web 页面来说,这仍然是一个不错的选择。


下面的代码展示了如何在 HtmlUnitDriver 中使用 Selenium 运行基本的测试。它之所以有效,是因为 InfoQ 的主页设计成了没有 JavaScript 也能正常工作。这个例子在 GitHub 库里,有Java 8Java 11版本。


package com.infoq.selenium;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.AfterEach;import org.junit.jupiter.api.BeforeEach;import org.junit.jupiter.api.Test;import org.openqa.selenium.By;import org.openqa.selenium.WebDriver;import org.openqa.selenium.htmlunit.HtmlUnitDriver;
import java.util.Set;import java.util.stream.Collectors;
public class HtmlUnitSeleniumIT {
protected WebDriver driver;
// ----------------------------------------------------
@BeforeEach public final void connect() { driver = new HtmlUnitDriver(); //driver.setJavascriptEnabled(true); }
@AfterEach public final void closeDriver() { if (driver != null) { driver.quit(); } }
@Test void qconDates() { driver.get(“https://www.infoq.com“);
Set<String> newYorkCity = driver.findElements(By.className(“qcon”)) .stream() .map(element -> element.getAttribute(“innerText”)) .filter(city -> city.trim().startsWith(“New York”)) .collect(Collectors.toSet()); assertEquals(1, newYorkCity.size(), “New York is an upcoming city”);
}}

复制代码


然而,取消启用 JavaScript 这行代码的注释就是另外一回事了。它会在抛出一堆 JavaScript 警告之后失败并报错:EcmaError: TypeError:无法调用未定义方法“then”。


由于许多页面在没有 JavaScript 的情况下根本无法加载,因此需要一个能更好地支持 JavaScript 的 Selenium 驱动程序。

PhantomJS

多年来,PhantomJS是一个很好的选择。它轻量级、无头,并且有很好的 JavaScript 支持。然而,2017 年 4 月,维护者退出,2018 年 3 月,该项目被正式放弃。我想念它。


通过阅读声明和评论可以发现,其意图显然是转移到 Chrome 驱动程序。对于任何新东西,我都不建议使用 PhantomJS。除了不受支持之外,我还将两个项目切换到 Chrome 驱动程序,因为对于当前大部分 JavaScript 库,PhantomJS 都不能很好地处理其中的 JavaScript。因为 Chrome 驱动程序使用的是真正的浏览器,所以这不是问题。

Chrome 驱动程序

Chrome 提供了一种无头模式,总体效果很好。最大的缺点是你需要能够安装 Chrome。你不需要 UI,但是并不一定能够安装软件。


Chrome 驱动程序也需要下载一个可执行文件。我在这里用了一点小技巧。我将可执行文件保存在与项目相同的目录中(或者保存在二进制存储库里,并将其复制到工作区中)。然后,我让 Java 测试本身设置权限。类似地,我让 Java 测试将 Java 流程中的系统属性设置为该位置。我知道这有点像作弊,但它确实让我几乎可以控制所有事情。“几乎”是因为它仍然需要安装 Chrome 本身。对我的个人项目,这非常有效。不过,当与他人共享代码时,它会崩溃,因为他们也需要下载可执行文件。


GitHub 库里有Java 8Java 11两个版本。两者都要求你下载可执行文件并将其替换到 chrome-driver 目录中。


package com.infoq.selenium;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import static org.junit.jupiter.api.Assertions.*;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Set;
import java.util.stream.Collectors;
public class ChromeSeleniumIT {
private static final boolean HEADLESS = true;
private static final String CHROME_DRIVER_DIRECTORY = “chrome-driver”;
protected WebDriver driver;
// ----------------------------------------------------
@BeforeEach
public final void connect() {
Path chrome = Paths.get(CHROME_DRIVER_DIRECTORY + “/chromedriver”);
chrome.toFile().setExecutable(true);
System.setProperty(“webdriver.chrome.driver”, chrome.toAbsolutePath().toString());
ChromeOptions chromeOptions = new ChromeOptions();
if (HEADLESS) {
chromeOptions.addArguments(“--headless”);
}
driver = new ChromeDriver(chromeOptions);
// https://github.com/seleniumhq/selenium-google-code-issue-archive/issues/27
((JavascriptExecutor) driver).executeScript(“window.alert = function(msg) { }“);
((JavascriptExecutor) driver).executeScript(“window.confirm = function(msg) { }“);
}
@AfterEach
public final void closeDriver() {
if (driver != null) {
driver.quit();
}
}
@Test
void qconDates() {
driver.get(“https://www.infoq.com”);
Set<String> newYorkCity = driver.findElements(By.className(“qcon”))
.stream()
.map(element -> element.getAttribute(“innerText”))
.filter(city -> city.trim().startsWith(“New York”))
.collect(Collectors.toSet());
assertEquals(1, newYorkCity.size(), “New York is an upcoming city”);
}

复制代码


这两行执行脚本用于解决我正在测试的另一个应用程序中的提示问题。我已经告诉驱动程序忽略它们。(虽然这里不需要它,但我发现我在任何使用 Chrome 驱动程序的地方都使用了它,所以我永远都不需要解决这个问题,这已经够痛苦的了!)


使用 Chrome 驱动程序的另一个缺点是它需要定期更新以支持 Chrome 的后续版本。

Gecko 驱动程序

Chrome 是第一个进行无头浏览器测试的,所以这是我最熟悉的一个。然而,Firefox 也有无头模式。就像 Chrome 一样。你可以下载Gecko驱动程序,并在你的 pom.xml 中使用 selenium-firefox-driver。

JBrowser 驱动程序

虽然我喜欢 Chrome 驱动程序,但它确实需要安装 Chrome。我有一个项目,我每天运行一个检查,看看 Oracle 认证目标是否有变化。在我运行这项检查的服务器上没有安装 Chrome。最近,Oracle 更新了他们的网站,更多地使用了 AJAX。PhantomJS 不再满足我的需求,所以我开始寻找一个更现代的驱动程序。


我找到了JBrowser驱动程序。该项目去年一直有定期的提交,包括针对 Selenium 版本的更新。它有良好的许可协议(Apache 2)。1.0.0 版本刚刚在 2018 年夏天发布。不过,1.0 之前的版本已经发布近 3 年了。


JBrowser 驱动程序最大的缺点是目前只支持 Oracle JDK Java 8。这个版本的 Java 将分别在 2019 年 1 月和 2020 年 12 月停止为企业用户和个人用户提供补丁。


关于 Java FX,请注意:


  • 在 Java 7 中,Java FX 是单独下载的;

  • 在 Java 8 中,Java FX 是 Oracle JDK 的组成部分,但不是 Open JDK 的组成部分;

  • 在 Java 11 中,Java FX 可以通过 Maven 依赖使用OpenJFX免费获得;

  • 同样,在 Java 11 中,Robot.java 类所在的包从com.sun.glass.ui变成了javafx.scene.robot。这意味着你不能只在 Open JDK 11 中使用 OpenJFX 的 JavaFX 版本,就期望 JBrowser 驱动程序能够正常工作。


代码很简单,Java 8版本在 GitHub 库中。



import com.machinepublishers.jbrowserdriver.JBrowserDriver;
import com.machinepublishers.jbrowserdriver.Settings;
import com.machinepublishers.jbrowserdriver.Timezone;
import com.machinepublishers.jbrowserdriver.UserAgent;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class JBrowserSeleniumIT {
protected WebDriver driver;
// ----------------------------------------------------
@BeforeEach
public final void connect() {
driver = new JBrowserDriver(Settings.builder()
.timezone(Timezone.AMERICA_NEWYORK)
.userAgent(UserAgent.CHROME).build());
// says 120 but is really 0
driver.manage().timeouts().pageLoadTimeout(120, TimeUnit.SECONDS);
}
@AfterEach
public final void closeDriver() {
if (driver != null) {
driver.quit();
}
}
@Test
void qconDates() {
driver.get(“https://www.infoq.com“);
Set<String> newYorkCity = driver.findElements(By.className(“qcon”))
.stream()
.map(element -> element.getAttribute(“innerText”))
.filter(city -> city.trim().startsWith(“New York”))
.collect(Collectors.toSet());
assertEquals(1, newYorkCity.size(), “New York is an upcoming city”);
}}
复制代码

小结——可选驱动对比

使用 Java 和 Selenium 进行无头浏览器测试有很多选择。就像任何良好的工程问题一样,需要在它们之间进行权衡。这张表列出了你的主要选项。我的经验是,如果你需要在没有安装真正浏览器的情况下运行无头 Selenium 驱动程序,那么你需要暂时使用 Java 8。


关于作者


Jeanne Boyarsky 是一名 Java 开发人员和兼职 ScrumMaster。她与人合著了 Wiley 出版的 OCA/OCP 8 认证书籍,并将针对认证的下一个版本进行更新。除了在 CodeRanch 做志愿者外,她还在一个高中机器人团队中指导程序员,并获得了导师奖。Jeanne 曾在 JavaOne、QCon、DevNexus 和 SpringOne 等会议上演讲。


查看英文原文:https://www.infoq.com/articles/headless-selenium-browsers


2019-01-15 18:118382
用户头像

发布了 729 篇内容, 共 465.7 次阅读, 收获喜欢 1542 次。

关注

评论

发布
暂无评论
发现更多内容

Gather在全球隐私保护领域的先锋地位

股市老人

PIRF-406-No Man is An Island…

EchoZhou

English

从 Elasticsearch 到 Easysearch:国产搜索型数据库的崛起与未来展望

极限实验室

elasticsearch 数据库· easysearch 搜索型数据库

php报错:Malformed UTF-8 characters, possibly incorrectly encoded

百度搜索:蓝易云

SOL链DApp智能合约代币质押挖矿分红系统开发模式讲解

V\TG【ch3nguang】

科大讯飞p30和小度k16 选哪个好

妙龙

科大讯飞 学习机

华为大咖说丨关于AI大模型发展的商业思考

华为云PaaS服务小智

人工智能 华为云

突破传统看车局限,3DCAT实时云渲染为东风日产奇骏赋能

3DCAT实时渲染

实时渲染 云3D渲染 云VR看车 虚拟云车展

博世(BOSCH)× Milvus:智能驾驶领域的数据挖掘革新

Zilliz

人工智能 大数据 AI 向量数据库 rag

打造全新AI创作、分享神器!橙篇APP上线,让更多人「自由创作、自在分享」

科技热闻

离开大厂为什么会“返贫”?比《逆行人生》更真实~~

博文视点Broadview

OSPF的基本概念

百度搜索:蓝易云

云服务器选多大带宽合适?

百度搜索:蓝易云

科大讯飞P30和步步高X3哪个值得买

妙龙

科大讯飞 学习机

科大讯飞p30和作业帮X28 区别对比

妙龙

科大讯飞 学习机

PHP通过Redis解决并发请求的操作问题

百度搜索:蓝易云

深度剖析京东JD商品详情API返回值结构:解锁商品数据的新维度

代码忍者

API 接口 API 测试

重塑商品热度洞察:关键字搜索API返回值中的深度商品热度分析新视角

代码忍者

API 接口 API 测试

人形机器人,距离“转正上岗”还差几步?

趣解商业

科技 人形机器人 优必选

科大讯飞p30和步步高a7 选哪个

妙龙

科大讯飞 学习机

项目安全管理工具选择指南

爱吃小舅的鱼

项目管理

Redis的数据类型到底有什么奥秘

百度搜索:蓝易云

区块链“NFT盲盒”模式系统的开发逻辑讲解

V\TG【ch3nguang】

NFT盲盒系统开发

Geekbench AI 命令行工具及故障排除

理理

如何在Python中使用情感分析API

幂简集成

Python API

OpenTelemetry:新一代的开源可观测性标准

乘云数字DataBuff

开源 #OpenTelemetry

动作冒险游戏推荐:泰拉瑞亚Terraria(Win&Mac)中文版

你的猪会飞吗

Mac游戏推荐 单机游戏

DAPP农场游戏系统开发:从概念到实现逻辑分析

V\TG【ch3nguang】

区块链开发定制交易所-dapp-公链-钱包-合约定制开发源码

V\TG【ch3nguang】

小度学习机Z30 怎么样

妙龙

学习机

基于STM32设计的简易手机

DS小龙哥

8月月更

你并不总希望在真正浏览器中进行测试:Selenium来营救_大前端_Jeanne Boyarsky_InfoQ精选文章