selenium无头浏览器
Selenium是众所周知的,功能强大的工具,用于在Web浏览器中进行自动测试。 尽管Selenium Web驱动程序支持所有主要的浏览器,但您并不总是希望在实际的浏览器中进行测试的成本。 无头的浏览器可以解救! 本文中的示例在GitHub存储库中 。 所有这些都与JUnit 5和Maven一起运行。 每个示例都注明了Java 11 vs Java 8支持。
无头浏览器无需用户界面(UI)即可运行。使用无头浏览器进行测试的一大好处是性能-由于无头浏览器没有UI,因此它们比真实的浏览器要快。
某些无头浏览器的另一个优点是-依赖关系。 在像Jenkins这样的持续集成服务器上进行测试时,该机器可能未安装真正的浏览器。 并且,根据您的环境,您可能没有安装该许可证的权限。
另一方面,需要安装“真实”浏览器的无头浏览器非常适合开发。 例如,Chrome和Firefox都可以选择以无头模式运行。 在调试Selenium脚本以暂时关闭无头模式并观察程序运行时,这确实很有帮助。 这样一来,您就可以直观地看到事情发生了什么。
过去,Selenium附带有一个内置的无头驱动程序,称为HtmlUnitDriver。 尽管仍支持此驱动程序,但它现在是一个单独的依赖项,并且毫不奇怪,它使用Html Unit框架。 在单页应用程序和很大程度上基于AJAX的页面之前,此驱动程序是一个不错的选择。 您可以选择是否运行页面JavaScript,它在内存中运行并且非常快。 对于其中包含大量HTML数据的网页来说,这仍然是一个不错的选择。
以下代码显示了如何运行将Selenium与HtmlUnitDriver结合使用的基本测试。 之所以可以使用它,是因为InfoQ的主页设计为无需JavaScript就可以正常工作。 GitHub存储库中的Java 8和Java 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支持的无头驱动程序。
多年来, PhantomJS是一个不错的选择。 它轻巧,无头,并且具有出色JavaScript支持。 但是,在2017年4月, 维护者下台了 ,在2018年3月,该项目被正式放弃 。 我想念它。
阅读公告和评论,目的显然是转移到Chrome驱动程序。 我不建议将PhantomJS用于新功能。 除了不被支持外,我还把两个项目切换到了Chrome驱动程序,因为PhantomJS对于最新JavaScript库JavaScript处理不够好。 由于Chrome驱动程序使用的是真实的浏览器,因此这不是问题。
Chrome提供了无头模式 ,整体上效果不错。 最大的缺点是您需要能够安装Chrome。 您不需要用户界面,但并非总是可以安装软件。
Chrome驱动程序还需要下载一个可执行文件 。 我在这里骗了一下。 我将可执行文件保存在与项目相同的目录中(或保存在二进制存储库中,然后将其复制到工作区中。)然后让Java测试本身设置权限。 同样,我进行了Java测试,将Java进程内的system属性设置为该位置。 我知道有点作弊,但它的确使几乎所有内容保持独立。 “几乎”是因为它仍然需要安装Chrome本身。 这对我的个人项目很有用。 在与他人共享代码时,尽管它们分崩离析,因为他们也需要下载可执行文件。
回购中有Java 8和Java 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。
Chrome率先参加了无头浏览器测试,因此我最有经验。 但是Firefox也具有无头模式 。 就像Chrome一样。 您可以下载Gecko驱动程序,并在pom.xml中使用selenium-firefox-driver
虽然我喜欢Chrome驱动程序,但确实需要安装Chrome。 我有一个项目,每天运行一次检查,以告诉我Oracle何时更改认证目标。 我在其上运行的服务器未安装Chrome。 最近,Oracle更新了他们的网站,使其变得更加沉重。 PhantomJS不再满足我的需求,因此我开始寻找更现代的驱动程序。
我找到了JBrowser驱动程序 。 去年有定期提交,包括对Selenium版本的更新。 它具有良好的许可证(Apache 2)。版本1.0.0刚刚于今年夏天发布。 但是,已经有将近三年的1.0之前的版本。
JBrowser驱动程序的最大缺点是,它们目前仅支持Oracle JDK Java 8。 这是Java版本,它将在2019年1月不再为企业用户提供补丁,并在2020年12月不再为个人用户提供补丁。
关于Java FX的注意事项:
代码简单明了, Java 8版本在GitHub存储库中。
package com.infoq.selenium;
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。
图书馆 | JavaScript的力量 | 支持Java 8 | 支持Java 11 | 需要安装浏览器 |
HTML单元驱动 | 低 | 是 | 是 | 没有 |
Phantom JS(不再受支持) | 中 | 是 | 没有 | 没有 |
Chrome驱动 | 高 | 是 | 是 | 是的-Chrome |
壁虎车手 | 高 | 是 | 是 | 是的– Firefox |
JBrowser驱动程序 | 高 | 是 | 没有 | 没有 |
selenium无头浏览器