NVIDIA 初创加速计划,免费加速您的创业启动 了解详情
写点什么

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

发布了 690 篇内容, 共 399.7 次阅读, 收获喜欢 1498 次。

关注

评论

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

云网资源如何搭乘「数字孪生」的快车道?

鲸品堂

数字孪生 设备 云网资源

浪潮云x乡村振兴:在烟台 十字融合勾勒数字乡村全新蓝图

浪潮云

云计算

新作!分布式系统韧性架构压舱石OpenChaos

华为云开发者联盟

Serverless 容器 分布式系统 混沌工程 OpenChaos

网站开发进阶(五十三)浅谈JS、Ajax、JQuery之间的关系

No Silver Bullet

JavaScript jquery ajax 5月月更

C语言_函数封装、变量的作用域

DS小龙哥

5月月更

深入了解python字典的有序特性

红毛丹

python 3.5+ 5月月更

这 BUG,绝了

AlwaysBeta

程序员

sealer 成为 CNCF Sandbox 项目,旨在构建分布式应用交付新标准

阿里巴巴云原生

阿里云 开源 容器 云原生

Go语言入门很简单:如何在 Go 语言中使用 MySQL

宇宙之一粟

Go 语言 MySQL 数据库 5月月更

云原生×实战派:向业务聚焦,数字创新时代的最佳选择

阿里巴巴云原生

阿里云 云原生 实战 电子书 案例集

网站开发进阶(五十)IE浏览器JS调试方法详解

No Silver Bullet

调试 5月月更

音视频行业玩家必读,如何实现生态合作+商业变现

华为云开发者联盟

音视频 华为云 实时音视频 实时音视频行业加速器 华为云SparkRTC

NFT 智能合约中的元数据(Metadata)

devpoint

区块链 智能合约 元数据 NFT

CMMI3级(低成熟度)与5级(高成熟度)到底有什么不同?

高山

CMMI CMMI高成熟度

keep-alive+导航守卫让缓存更精确

空城机

Vue 5月月更

高效学习C++基础部分&话题挑战赛

安然无虞

5月月更

奉劝想把编程学好的学弟们 · 如何高效学习编程?

安然无虞

5月月更

ACK One 构建应用系统的两地三中心容灾方案

阿里巴巴云原生

阿里云 容器 云原生 容灾

一种基于事件驱动思想的 SAP 系统集成二次开发方法介绍

Jerry Wang

云计算 SAP 二次开发 5月月更

他教全世界程序员怎么写好代码,而且将所有答案写在这本书里!

博文视点Broadview

知名整机厂商中科曙光加入,携手龙蜥社区共建应用生态

OpenAnolis小助手

龙蜥社区 CLA 龙腾计划 中科曙光

兼容PyTorch,25倍性能加速,OneFlow“超速”了

OneFlow

人工智能 深度学习 性能优化 oneflow

01-Linux 系统简介

爱好编程进阶

程序员 后端开发

PHP基础语法1

乌龟哥哥

5月月更

为什么企业一定要拥有知识管理的能力

小炮

企业知识管理

kubernetes下的Nginx加Tomcat三部曲之二:细说开发

程序员欣宸

Java Kubernetes 5月月更

【PIMF】手把手教会在OpenHarmony仓库不使git命令提交PR参与社区贡献

离北况归

OpenHarmony Openharmony啃论文俱乐部 PIMF团队

线程简介

急需上岸的小谢

5月月更

YUV色彩空间

Loken

5月月更

[Day39]-[二叉树] 二叉搜索树中第K小的元素

方勇(gopher)

LeetCode 二叉树 数据结构算法

深入浅出PID算法

劼哥stone

算法 工业互联网 PID

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