发布在即!企业 AIGC 应用程度测评,3 步定制专属评估报告。抢首批测评权益>>> 了解详情
写点什么

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

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

关注

评论

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

文件打开标识O_CLOEXEC简介

SkyFire

Linux 文件描述符

架构训练营第10期模块6作业

Geek_4db2d5

订单流量录制与回放探索实践

得物技术

Java 运维 后端 稳定生产

现实中的量子计算机有望进化成《流量地球2》中的MOSS吗?

博文视点Broadview

浪潮云:以数据云IBP释放数据要素力量

浪潮云

云计算 数据云

全球化安全生产 & 质量保障体系建设探索

阿里技术

质量保障 安全生产 全球化技术能力

成为海上霸总,全靠5G?

脑极体

5G

OKR之剑·实战篇05:OKR致胜法宝-氛围&业绩双轮驱动(上)

vivo互联网技术

团队管理 OKR

linux 磁盘挂载

平凡人生

在 Asp.Net Core 中什么是认证和授权

newbe36524

C# Kubernetes

全景剖析阿里云容器网络数据链路(三):Terway ENIIP

阿里巴巴云原生

阿里云 云原生 云原生容器

易观千帆 | 12月用户体验GX评测:国有行及股份行持续领跑,农信社用户体验关注提升

易观分析

金融 手机银行

数据可视化大屏项目,我是如何实现多屏间的数据通信

梁木由

程序员 前端 前端开发

内存数据库如何发挥内存优势?

陈橘又青

数据库

SpringBoot实现电子文件签字+合同系统

程序员大彬

springboot

一文教你如何重新认识用户

蔡农曰

互联网 产品经理 消费者 需求设计

linux 查看操作系统版本

平凡人生

架构实战营第10期模块六

刘博

四点聚焦亚马逊2022财报,AWS收入801亿美元,同比增长20%,年度增长率29%

B Impact

富士康CDO史喆:数字化和智能化为何要打造开放系统,引入外部合作?

B Impact

微博系统中”微博评论“的高性能高可用计算架构

Geek_e5f2e5

FL水果软件2023最新中文版本在哪里下载?

茶色酒

FL Studio21

智能合约佛萨奇系统开发,佛萨奇2.0源码搭建

薇電13242772558

统一观测丨如何使用 Prometheus 监控 MySQL

阿里巴巴云原生

MySQL 阿里云 云原生 #Prometheus

CleanMyMac4.12.4最新中文版本下载

茶色酒

CleanMyMac X

IntelliJ IDEA 的 Code Coverage 测试

HoneyMoose

来看一个 ChatGPT 有关程序员的笑话

HoneyMoose

单体应用、SOA架构、微服务架构有哪些优劣势?

FN0

微服务架构 组件化 SOA

Guitar Pro8和谐版安装包下载教程

茶色酒

Guitar Pro8

2023最新H5前端阅读书单推荐

kcodez

前端 H5 React

Java高手速成 | JSP的MVC模式

TiAmo

mvc jsp

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