• Selenium 自动化 | 案例实战篇


    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() 方法。

    1. package com.devtools;
    2. import org.openqa.selenium.chrome.ChromeDriver;
    3. import org.openqa.selenium.devtools.DevTools;
    4. import java.util.HashMap;
    5. import java.util.Map;
    6. public class SetDeviceMode {
    7. final static String PROJECT_PATH = System.getProperty("user.dir");
    8. public static void main(String[] args){
    9. System.setProperty("webdriver.chrome.driver", PROJECT_PATH + "/src/main/resources/chromedriver");
    10. ChromeDriver driver;
    11. driver = new ChromeDriver();
    12. DevTools devTools = driver.getDevTools();
    13. devTools.createSession();
    14. Map deviceMetrics = new HashMap()
    15. {{
    16. put("width", 600);
    17. put("height", 1000);
    18. put("mobile", true);
    19. put("deviceScaleFactor", 50);
    20. }};
    21. driver.executeCdpCommand("Emulation.setDeviceMetricsOverride", deviceMetrics);
    22. driver.get("https://www.google.com");
    23. }
    24. }

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

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

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

    图片

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

    模拟地理位置

    在许多情况下,我们需要测试特定的基于位置的功能,例如优惠、基于位置的价格等。为此,我们可以使用DevTools API来模拟位置。

    1. @Test
    2. public void mockLocation(){
    3. devTools.send(Emulation.setGeolocationOverride(
    4. Optional.of(48.8584),
    5. Optional.of(2.2945),
    6. Optional.of(100)));
    7. driver.get("https://mycurrentlocation.net/");
    8. try {
    9. Thread.sleep(30000);
    10. } catch (InterruptedException e) {
    11. e.printStackTrace();
    12. }
    13. }

    模拟网络速度

    许多用户通过连接到 Wi-Fi 或蜂窝网络的手持设备访问 Web 应用程序。遇到信号弱的网络信号,因此互联网连接速度较慢是很常见的。

    在互联网连接速度较慢(2G)或间歇性断网的情况下,测试应用程序在这种条件下的行为可能很重要。

    伪造网络连接的 CDP 命令是 Network.emulateNetworkConditions。关于此命令的必需和可选参数的信息可以在文档中找到。

    通过访问 Chrome DevTools,就可以模拟这些场景。让我们看看如何做到这一点。

    1. package com.devtools;
    2. import org.openqa.selenium.chrome.ChromeDriver;
    3. import org.openqa.selenium.devtools.DevTools;
    4. import org.openqa.selenium.devtools.network.Network;
    5. import org.openqa.selenium.devtools.network.model.ConnectionType;
    6. import java.util.HashMap;
    7. import java.util.Map;
    8. import java.util.Optional;
    9. public class SetNetwork {
    10. final static String PROJECT_PATH = System.getProperty("user.dir");
    11. public static void main(String[] args){
    12. System.setProperty("webdriver.chrome.driver", PROJECT_PATH + "/src/main/resources/chromedriver");
    13. ChromeDriver driver;
    14. driver = new ChromeDriver();
    15. DevTools devTools = driver.getDevTools();
    16. devTools.createSession();
    17. devTools.send(Network.enable(Optional.empty(), Optional.empty(), Optional.empty()));
    18. devTools.send(Network.emulateNetworkConditions(
    19. false,
    20. 20,
    21. 20,
    22. 50,
    23. Optional.of(ConnectionType.CELLULAR2G)
    24. ));
    25. driver.get("https://www.google.com");
    26. }
    27. }

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

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

    捕获HTTP请求

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

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

    1. package com.devtools;
    2. import org.openqa.selenium.chrome.ChromeDriver;
    3. import org.openqa.selenium.devtools.DevTools;
    4. import org.openqa.selenium.devtools.network.Network;
    5. import java.util.Optional;
    6. public class CaptureNetworkTraffic {
    7. private static ChromeDriver driver;
    8. private static DevTools chromeDevTools;
    9. final static String PROJECT_PATH = System.getProperty("user.dir");
    10. public static void main(String[] args){
    11. System.setProperty("webdriver.chrome.driver", PROJECT_PATH + "/src/main/resources/chromedriver");
    12. driver = new ChromeDriver();
    13. chromeDevTools = driver.getDevTools();
    14. chromeDevTools.createSession();
    15. chromeDevTools.send(Network.enable(Optional.empty(), Optional.empty(), Optional.empty()));
    16. chromeDevTools.addListener(Network.requestWillBeSent(),
    17. entry -> {
    18. System.out.println("Request URI : " + entry.getRequest().getUrl()+"\n"
    19. + " With method : "+entry.getRequest().getMethod() + "\n");
    20. entry.getRequest().getMethod();
    21. });
    22. driver.get("https://www.google.com");
    23. chromeDevTools.send(Network.disable());
    24. }
    25. }

    开始捕获网络流量的 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响应可用时触发此事件,我们可以监听URL、响应头、响应代码等。要获取响应正文,请使用Network.getResponseBody方法。

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

    访问控制台日志

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

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

    1. package com.devtools;
    2. import org.openqa.selenium.chrome.ChromeDriver;
    3. import org.openqa.selenium.devtools.DevTools;
    4. import org.openqa.selenium.devtools.log.Log;
    5. public class CaptureConsoleLogs {
    6. private static ChromeDriver driver;
    7. private static DevTools chromeDevTools;
    8. final static String PROJECT_PATH = System.getProperty("user.dir");
    9. public static void main(String[] args){
    10. System.setProperty("webdriver.chrome.driver", PROJECT_PATH + "/src/main/resources/chromedriver");
    11. driver = new ChromeDriver();
    12. chromeDevTools = driver.getDevTools();
    13. chromeDevTools.createSession();
    14. chromeDevTools.send(Log.enable());
    15. chromeDevTools.addListener(Log.entryAdded(),
    16. logEntry -> {
    17. System.out.println("log: "+logEntry.getText());
    18. System.out.println("level: "+logEntry.getLevel());
    19. });
    20. driver.get("https://testersplayground.herokuapp.com/console-5d63b2b2-3822-4a01-8197-acd8aa7e1343.php");
    21. }
    22. }

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

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

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

    捕获性能指标

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

    我们能够在每次构建时验证这些指标吗?是的,我们可以!

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

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

    1. package com.devtools;
    2. import org.openqa.selenium.chrome.ChromeDriver;
    3. import org.openqa.selenium.devtools.DevTools;
    4. import org.openqa.selenium.devtools.performance.Performance;
    5. import org.openqa.selenium.devtools.performance.model.Metric;
    6. import java.util.Arrays;
    7. import java.util.List;
    8. import java.util.stream.Collectors;
    9. public class GetMetrics {
    10. final static String PROJECT_PATH = System.getProperty("user.dir");
    11. public static void main(String[] args){
    12. System.setProperty("webdriver.chrome.driver", PROJECT_PATH + "/src/main/resources/chromedriver");
    13. ChromeDriver driver = new ChromeDriver();
    14. DevTools devTools = driver.getDevTools();
    15. devTools.createSession();
    16. devTools.send(Performance.enable());
    17. driver.get("https://www.google.org");
    18. List metrics = devTools.send(Performance.getMetrics());
    19. List metricNames = metrics.stream()
    20. .map(o -> o.getName())
    21. .collect(Collectors.toList());
    22. devTools.send(Performance.disable());
    23. List metricsToCheck = Arrays.asList(
    24. "Timestamp", "Documents", "Frames", "JSEventListeners",
    25. "LayoutObjects", "MediaKeySessions", "Nodes",
    26. "Resources", "DomContentLoaded", "NavigationStart");
    27. metricsToCheck.forEach( metric -> System.out.println(metric +
    28. " is : " + metrics.get(metricNames.indexOf(metric)).getValue()));
    29. }
    30. }

    首先,我们通过调用 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 中调用此命令的方法。

    1. package com.devtools;
    2. import org.apache.commons.codec.binary.Base64;
    3. import org.openqa.selenium.By;
    4. import org.openqa.selenium.chrome.ChromeDriver;
    5. import org.openqa.selenium.devtools.DevTools;
    6. import org.openqa.selenium.devtools.network.Network;
    7. import org.openqa.selenium.devtools.network.model.Headers;
    8. import java.util.HashMap;
    9. import java.util.Map;
    10. import java.util.Optional;
    11. public class SetAuthHeader {
    12. private static final String USERNAME = "guest";
    13. private static final String PASSWORD = "guest";
    14. final static String PROJECT_PATH = System.getProperty("user.dir");
    15. public static void main(String[] args){
    16. System.setProperty("webdriver.chrome.driver", PROJECT_PATH + "/src/main/resources/chromedriver");
    17. ChromeDriver driver = new ChromeDriver();
    18. //Create DevTools session and enable Network
    19. DevTools chromeDevTools = driver.getDevTools();
    20. chromeDevTools.createSession();
    21. chromeDevTools.send(Network.enable(Optional.empty(), Optional.empty(), Optional.empty()));
    22. //Open website
    23. driver.get("https://jigsaw.w3.org/HTTP/");
    24. //Send authorization header
    25. Map headers = new HashMap<>();
    26. String basicAuth ="Basic " + new String(new Base64().encode(String.format("%s:%s", USERNAME, PASSWORD).getBytes()));
    27. headers.put("Authorization", basicAuth);
    28. chromeDevTools.send(Network.setExtraHTTPHeaders(new Headers(headers)));
    29. //Click authentication test - this normally invokes a browser popup if unauthenticated
    30. driver.findElement(By.linkText("Basic Authentication test")).click();
    31. String loginSuccessMsg = driver.findElement(By.tagName("html")).getText();
    32. if(loginSuccessMsg.contains("Your browser made it!")){
    33. System.out.println("Login successful");
    34. }else{
    35. System.out.println("Login failed");
    36. }
    37. driver.quit();
    38. }
    39. }

    我们首先使用 DevTools 对象创建一个会话,并启用 Network。这在第25-26行中展示。

    接下来,我们打开我们的网站,然后创建用于发送的身份验证标头。

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

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

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

    总结

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

    最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:

    在这里插入图片描述

    这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!   

  • 相关阅读:
    第1章 模拟器/真机对后端数据的获取之后端实现
    15分钟面试被5连CALL,你扛得住么?
    GPU -- 图形处理器(显卡)
    python爬取boss直聘数据(selenium+xpath)
    学生管理系统(python实现)
    ARM编程模型-常用指令集
    Linux 权限相关例题练习
    ABAP技术总结2022.8.30(ALV和smart forms)
    OkGo - 一个基于okhttp的标准RESTful风格的网络框架
    EMQX 集群节点数据转发
  • 原文地址:https://blog.csdn.net/qq_48811377/article/details/133701837