当前位置: 首页 > 图灵资讯 > 技术篇> Selenium - 用这个力量做任何你想做的事情

Selenium - 用这个力量做任何你想做的事情

来源:图灵教育
时间:2023-06-26 15:39:51

大家好,我是Yuan。今天,我将介绍Selenium自动化浏览器。就是这样!你可以用这种力量做任何你想做的事。

“getDevTools() 方法返回新的 Chrome DevTools 允许您使用的对象 send() 方法发送针对 CDP 的内置 Selenium 命令。这些命令是包装方法,用于调用 CDP 函数更清晰、更简单。"

——SHAMA UGALE

首先,什么是 Chrome DevTools?

Chrome DevTools 简介

Chrome DevTools 基于一组直接内置 Chromium 浏览器(如 Chrome、Opera 和 Microsoft Edge)该工具用于帮助开发人员调试和研究网站。

借助 Chrome DevTools,开发人员可以更深入地访问网站,并且可以:

  • 检查 DOM 中的元素
  • 即时编辑元素和 CSS
  • 检查和监控网站的性能
  • 模拟用户的地理位置
  • 模拟网络速度更快/更慢
  • 执行和调试 JavaScript
  • 查看控制台日志
  • 等等
Selenium 4 Chrome DevTools API

Selenium 是支持 web 一系列浏览器自动化工具和图书馆综合项目。Selenium 4 添加了对 Chrome DevTools API 本地支持。在这些新的帮助下。 API,现在我们的测试可以:

  • 捕获和监控网络流量和性能
  • 位置感知测试、本地化和国际化测试用于模拟地理位置
  • 改变设备模式,测试应用程序的响应性

这只是冰山一角!

Selenium 4 引入了新的 ChromiumDriver 类别包括两种访问方法 Chrome DevTools:getDevTools() 和 executeCdpCommand()。

getDevTools() 方法返回新的 DevTools 允许您使用的对象 send() 方法发送针对 CDP 的内置 Selenium 命令。这些命令是包装方法,用于调用 CDP 函数更清晰、更简单。

executeCdpCommand() 该方法也允许您执行 CDP 方法,但更原始。不使用包装 API,相反,允许您直接进入 Chrome DevTools 命令和命令的参数。如果某个 CDP 命令没有 Selenium 包装 API,或者你想要以和 Selenium API 可以使用不同的调用方式 executeCdpCommand()。

像 ChromeDriver 和 EdgeDriver 这样的基于 Chromium 现在继承自己的驱动程序 ChromiumDriver,因此,您也可以访问这些驱动程序 Selenium CDP API。

让我们探索如何利用这些新的 Selenium 4 API 解决各种使用案例。

模拟设备模式

我们今天构建的大多数应用程序都是响应性的,以满足各种平台、设备(如手机、平板电脑、可穿戴设备、桌面)和屏幕方向的终端用户的需求。

作为测试人员,我们可能希望将我们的应用程序放置在不同的尺寸中,以触发应用程序的响应性。

如何使用我们 Selenium 的新 CDP 实现这一点的功能?

用于修改设备测量 CDP 命令是 Emulation.setDeviceMetricsOverride,此命令需要输入宽度、高度、移动设备标志和设备缩放因子。这四个键在这个场景中是必要的,但也有一些可选键。

在我们的 Selenium 我们可以在测试中使用它 DevTools::send() 内置方法和使用方法 setDeviceMetricsOverride() 但这是命令 Selenium API 接受 12 个参数 - 除了 4 除了必要的参数,还有必要的参数 8 可选参数。我们不需要发送这个 8 我们可以传递任何可选参数中的任何一个 Optional.empty()。

然而,为了简化这个过程,只传输所需的参数,我将使用下面代码中的原始参数 executeCdpCommand() 方法。

package com.devtools;import org.openqa.selenium.chrome.ChromeDriver;import org.openqa.selenium.devtools.DevTools;import java.util.HashMap;import java.util.Map;public class SetDeviceMode {    final static String PROJECT_PATH = System.getProperty("user.dir");    public static void main(String[] args){        System.setProperty("webdriver.chrome.driver", PROJECT_PATH + "/src/main/resources/chromedriver");        ChromeDriver driver;        driver = new ChromeDriver();        DevTools devTools = driver.getDevTools();        devTools.createSession();        Map deviceMetrics = new HashMap()        {{            put("width", 600);            put("height", 1000);            put("mobile", true);            put("deviceScaleFactor", 50);        }};        driver.executeCdpCommand("Emulation.setDeviceMetricsOverride", deviceMetrics);        driver.get("https://www.google.com");    }}

在第19行,我创建了一个包含此命令所需键的映射。

然后在第26行,我调用 executeCdpCommand() 方法和传递两个参数:命令名称 "Emulation.setDeviceMetricsOverride以及包含参数的设备测量映射。

在第27行,我打开渲染了我提供的规格 "Google" 主页,如下图所示。

Selenium - 用这个力量做任何你想做的事情_后端

借助像 Applitools Eyes 我们不仅可以使用这些新的解决方案 Selenium 命令可以从不同的角度快速测试,并在规模上保持任何不一致性。Eyes 足够智能,不会由不同的浏览器和视图引起 UI 变化报告中小且难以察觉的错误结果。

模拟地理位置

在许多情况下,我们需要测试基于位置的特定功能,如折扣、基于位置的价格等。因此,我们可以使用Devtols 模拟位置的API。

@Test    public void mockLocation(){        devTools.send(Emulation.setGeolocationOverride(                Optional.of(48.8584),                Optional.of(2.2945),                Optional.of(100)));        driver.get("https://mycurrentlocation.net/");        try {            Thread.sleep(30000);        } catch (InterruptedException e) {            e.printStackTrace();        }    }

在第21行,我们通过调用 getDevTools() 方法获取 DevTools 对象。然后,我们调用 send() 方法来启用 Network,并再次调用 send() 传递内置命令的方法 Network.emulateNetworkConditions() 与我们希望与此命令一起发送的参数。

最后,我们使用模拟网络条件打开它 Google 首页。

捕获HTTP请求

使用 DevTools,我们可以捕获由应用程序启动的应用程序 HTTP 请求、访问方法、数据、头部信息等。

让我们看看如何使用示例代码捕获 HTTP 请求、URI 以及请求方法。

package com.devtools;import org.openqa.selenium.chrome.ChromeDriver;import org.openqa.selenium.devtools.DevTools;import org.openqa.selenium.devtools.network.Network;import java.util.Optional;public class CaptureNetworkTraffic {    private static ChromeDriver driver;    private static DevTools chromeDevTools;    final static String PROJECT_PATH = System.getProperty("user.dir");    public static void main(String[] args){        System.setProperty("webdriver.chrome.driver", PROJECT_PATH + "/src/main/resources/chromedriver");        driver = new ChromeDriver();        chromeDevTools = driver.getDevTools();        chromeDevTools.createSession();        chromeDevTools.send(Network.enable(Optional.empty(), Optional.empty(), Optional.empty()));        chromeDevTools.addListener(Network.requestWillBeSent(),                entry -> {                    System.out.println("Request URI : " + entry.getRequest().getUrl()+"\n"                    + " With method : "+entry.getRequest().getMethod() + "\n");                    entry.getRequest().getMethod();                });        driver.get("https://www.google.com");        chromeDevTools.send(Network.disable());    }}

开始捕获网络流量 CDP 命令是 Network.enable。文档中可以找到本命令的必要性和可选参数的信息。

第22行使用我们的代码 DevTools::send() 方法发送 Network.enable CDP 使用网络流量捕获命令。

第23行为监控应用程序发送的所有请求增加了监控器。我们使用应用程序捕获的每个请求 getRequest().getUrl() 提取 URL,并使用 getRequest().getMethod() 提取 HTTP 方法。

我们打开了第29行 Google 主页打印在控制台上发出的所有请求 URI 和 HTTP 方法。

一旦我们完成了要求的捕获,我们可以发送它 Network.disable 的 CDP 如第30行所示,命令停止捕获网络流量。

拦截HTTP响应

我们将使用Network来拦截响应.responsereceived事件。当HTTP响应可用时,我们可以监控URLL、响应头、响应代码等。要获得响应文本,请使用Network.getresponsebody方法。

@Test    public void validateResponse() {        final RequestId[] requestIds = new RequestId[1];        devTools.send(Network.enable(Optional.of(100000000), Optional.empty(), Optional.empty()));        devTools.addListener(Network.responseReceived(), responseReceived -> {            if (responseReceived.getResponse().getUrl().contains("api.zoomcar.com")) {                System.out.println("URL: " + responseReceived.getResponse().getUrl());                System.out.println("Status: " + responseReceived.getResponse().getStatus());                System.out.println("Type: " + responseReceived.getType().toJson());                responseReceived.getResponse().getHeaders().toJson().forEach((k, v) -> System.out.println((k + ":" + v)));                requestIds[0] = responseReceived.getRequestId();                System.out.println("Response Body: \n" + devTools.send(Network.getResponseBody(requestIds[0])).getBody() + "\n");            }        });        driver.get("https://www.zoomcar.com/bangalore");        driver.findElement(By.className("search")).click();    }

访问控制台日志

我们都依靠日志来调试和分析故障。在测试和处理具有特定数据或条件的应用程序时,日志可以帮助我们调试和捕获错误信息,并提供更多信息 Chrome DevTools 控制台选项卡中发布的见解。

我们可以通过调用 CDP 我们的日志命令通过我们的日志命令 Selenium 如下所示,脚本捕获控制台日志。

package com.devtools;import org.openqa.selenium.chrome.ChromeDriver;import org.openqa.selenium.devtools.DevTools;import org.openqa.selenium.devtools.log.Log;public class CaptureConsoleLogs {        private static ChromeDriver driver;    private static DevTools chromeDevTools;    final static String PROJECT_PATH = System.getProperty("user.dir");    public static void main(String[] args){        System.setProperty("webdriver.chrome.driver", PROJECT_PATH + "/src/main/resources/chromedriver");        driver = new ChromeDriver();        chromeDevTools = driver.getDevTools();        chromeDevTools.createSession();        chromeDevTools.send(Log.enable());        chromeDevTools.addListener(Log.entryAdded(),                logEntry -> {                    System.out.println("log: "+logEntry.getText());                    System.out.println("level: "+logEntry.getLevel());                });        driver.get("https://testersplayground.herokuapp.com/console-5d63b2-3822-4a01-8197-acd8a7.图灵");    }}

第19行使用我们的代码 DevTools::send() 启用控制台日志捕获。

然后,我们添加了一个监控器来捕获应用程序记录的所有控制台日志。我们使用应用程序捕获的每个日志 getText() 提取日志文本并使用该方法 getLevel() 提取日志级别的方法。

最后,打开应用程序,捕获应用程序发布的控制台错误日志。

捕获性能指标

在当今快节奏的世界里,我们应该以如此快的速度迭代构建软件,我们也应该迭代检测性能瓶颈。性能差的网站和加载慢的页面会让客户不满意。

这些指标每次施工都能验证吗?是的,我们可以!

捕获性能指标 CDP 命令是 Performance.enable。文档中可以找到关于此命令的信息。

让我们看看如何在那里 Selenium 4 和 Chrome DevTools API 完成这个过程。

package com.devtools;import org.openqa.selenium.chrome.ChromeDriver;import org.openqa.selenium.devtools.DevTools;import org.openqa.selenium.devtools.performance.Performance;import org.openqa.selenium.devtools.performance.model.Metric;import java.util.Arrays;import java.util.List;import java.util.stream.Collectors;public class GetMetrics {    final static String PROJECT_PATH = System.getProperty("user.dir");    public static void main(String[] args){        System.setProperty("webdriver.chrome.driver", PROJECT_PATH + "/src/main/resources/chromedriver");        ChromeDriver driver = new ChromeDriver();        DevTools devTools = driver.getDevTools();        devTools.createSession();        devTools.send(Performance.enable());        driver.get("https://www.google.org");        List<Metric> metrics = devTools.send(Performance.getMetrics());        List<String> metricNames = metrics.stream()                .map(o -> o.getName())                .collect(Collectors.toList());        devTools.send(Performance.disable());        List<String> metricsToCheck = Arrays.asList(                "Timestamp", "Documents", "Frames", "JSEventListeners",                "LayoutObjects", "MediaKeySessions", "Nodes",                "Resources", "DomContentLoaded", "NavigationStart");        metricsToCheck.forEach( metric -> System.out.println(metric +                " is : " + metrics.get(metricNames.indexOf(metric)).getValue()));    }}

首先,我们通过调用 DevTools 的 createSession() 创建会话的方法,如第19行所示。

接下来,我们通过将军 Performance.enable() 命令发送给 send() 来启用 DevTools 如第20行所示,捕获性能指标。

性能捕获一旦启用,我们就可以打开应用程序 Performance.getMetrics() 命令发送给 send()。这将返回一个 Metric 对象列表,我们可以通过流式处理获得所有捕获指标的名称,如第25行所示。

然后,我们通过将军 Performance.disable() 命令发送给 send() 如第29行所示,禁用性能捕获。

为了查看我们感兴趣的指标,我们定义了一个名称 metricsToCheck 列表,然后通过循环遍历列表打印指标值。

基本身份验证

在 Selenium 在中间,它不能与浏览器弹出窗口交互,因为它只能与浏览器弹出窗口交互 DOM 交互元素。这对身份验证对话框等弹出窗口构成了挑战。

我们可以使用它 CDP API 直接与 DevTools 处理身份验证来绕过这个问题。设置要求的附加标头 CDP 命令是 Network.setExtraHTTPHeaders。

以下是在 Selenium 4 调用此命令的方法。

package com.devtools;import org.apache.commons.codec.binary.Base64;import org.openqa.selenium.By;import org.openqa.selenium.chrome.ChromeDriver;import org.openqa.selenium.devtools.DevTools;import org.openqa.selenium.devtools.network.Network;import org.openqa.selenium.devtools.network.model.Headers;import java.util.HashMap;import java.util.Map;import java.util.Optional;public class SetAuthHeader {  private static final String USERNAME = "guest";  private static final String PASSWORD = "guest";  final static String PROJECT_PATH = System.getProperty("user.dir");  public static void main(String[] args){    System.setProperty("webdriver.chrome.driver", PROJECT_PATH + "/src/main/resources/chromedriver");    ChromeDriver driver = new ChromeDriver();    //Create DevTools session and enable Network    DevTools chromeDevTools = driver.getDevTools();    chromeDevTools.createSession();    chromeDevTools.send(Network.enable(Optional.empty(), Optional.empty(), Optional.empty()));    //Open website    driver.get("https://jigsaw.w3.org/HTTP/");    //Send authorization header    Map<String, Object> headers = new HashMap<>();    String basicAuth ="Basic " + new String(new Base64().encode(String.format("%s:%s", USERNAME, PASSWORD).getBytes()));    headers.put("Authorization", basicAuth);    chromeDevTools.send(Network.setExtraHTTPHeaders(new Headers(headers)));    //Click authentication test - this normally invokes a browser popup if unauthenticated    driver.findElement(By.linkText("Basic Authentication test")).click();    String loginSuccessMsg = driver.findElement(By.tagName("html")).getText();    if(loginSuccessMsg.contains("Your browser made it!")){      System.out.println("Login successful");    }else{      System.out.println("Login failed");    }    driver.quit();  }}

我们先用 DevTools 对象创建会话并启用 Network。展示在第25-26行。

接下来,我们打开我们的网站,创建身份验证标头进行发送。

在第35行,我们将 setExtraHTTPHeaders 命令发送到 send()同时发送标头数据。这部分将验证我们的身份,并允许我们绕过浏览器弹出窗口。

为了测试此功能,我们点击了基本身份验证测试链接。如果您手动尝试此操作,您将看到浏览器弹出窗口要求您登录。但由于我们发送了身份验证标头,这个弹出窗口不会出现在我们的脚本中。

相反,我们会收到“你的浏览器登录成功了!”。

总结

通过添加 CDP API,Selenium 它变得更强大了。现在,我们可以加强我们的测试和捕获 HTTP 网络流量,收集性能指标,处理身份验证,模拟地理位置、时区和设备模式。以及 Chrome DevTools 任何其他可能出现的功能!

参考:

  1. 官方网站Selenium:https://www.selenium.dev/
  2. Selenium文档:https://www.selenium.dev/documentation/en/
  3. Selenium教程:https://www.selenium.dev/documentation/en/getting_started/
  4. Selenium API文档:https://www.selenium.dev/selenium/docs/api/py/index.html