速来报名!AICon北京站鸿蒙专场~ 了解详情
写点什么

你并不总希望在真正浏览器中进行测试: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:118408
用户头像

发布了 741 篇内容, 共 480.4 次阅读, 收获喜欢 1549 次。

关注

评论

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

逃离过度努力陷阱

FunTester

FunTester 湛卢 轻松主义

RDP是什么意思?有什么用?

行云管家

运维 网络协议 RDP

百度荣获 “2021年中国网络安全产业联盟数据安全工作委员会突出贡献奖”

百度开发者中心

盘点近期虎符交易所上线的项目

区块链前沿News

虎符交易所

Tapdata PDK 生态共建计划启动!MongoDB、Doris、OceanBase、PolarDB等十余家厂商首批加入

MongoDB中文社区

在Rainbond上部署高可用Apollo集群

北京好雨科技有限公司

自助洗车设备全套多少钱?有了解的吗

共享电单车厂家

自助洗车机价格 自助洗车加盟 自助洗车设备多少钱

不再单调!快来自定义你的专属背景~

优麒麟

Linux 开源 操作系统 优麒麟 用户登录

PHP项目微信提现功能代码详解

CRMEB

重磅!百度安全参编的国家标准《信息安全技术 术语》正式发布

百度开发者中心

易周金融观点 | 数字人民币试点扩大带动增量场景需求

易观分析

金融 数字化人民币

多个角度论证SeekTiger 生态核心STI的魅力

西柚子

如何通过Password Vault的XSS漏洞窃取用户密码信息

喀拉峻

网络安全 XSS

如何设计帮助中心才能真正地帮助客户解决问题?

小炮

帮助中心

零信任访问控制下企业ABAC的实施问题

Geek_2d6073

netty系列之:netty中的自动解码器ReplayingDecoder

程序那些事

Java Netty 程序那些事 4月月更

crontab命令详细介绍教程,快来围观

CRMEB

“囤菜新宠”预制菜,会是生鲜电商的破局点吗?

易观分析

Docker 实战教程之从入门到提高(一)

汪子熙

Docker Kubernetes 容器 镜像 4月月更

SAE 联合乘云至达与谱尼测试携手共同抗疫

阿里巴巴云原生

AliPLC 智能丢包补偿算法,提升弱网环境的通话质量

阿里云CloudImagine

音视频 音频 视频云 音频算法 丢包补偿

“转型·破局” 看数字化会员如何重塑企业竞争力

科技热闻

jackson学习之六:常用类注解

程序员欣宸

4月月更

俄乌战争下的国产数据库替换思考-墨天轮

墨天轮

数据库 oracle 达梦 gbase8a

直播预告|年营业额百亿的企业都在如何做数字化转型

云智慧AIOps社区

数字化转型 AIOPS 解决方案 智能运维

@所有高校师生,2022全国大学生物联网设计竞赛火热开启,限量礼品等你来拿!

HarmonyOS开发者

HarmonyOS 物联网设计竞赛

杭州等保测评公司有哪些?分别叫什么?如何能查到?

行云管家

等保 等级保护 等保测评 杭州

eBPF Cilium实战(2) - 底层网络可观测性

北京好雨科技有限公司

Docker Kubernetes PaaS cilium

ETL 和数仓建模的设计思路!

五分钟学大数据

4月月更

大咖说|阿里巴巴副总裁陈龙:数字技术将在绿色低碳转型中发挥关键作用

大咖说

阿里巴巴 数字化 碳中和

在Linux环境下安装SQLserver2017

春风十里

数据库 Linux SqlServer

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