Selenium 自動化 | 案例實戰篇

Chrome DevTools 簡介

Chrome DevTools 是一組直接內置在基于 Chromium 的瀏覽器(如 Chrome、Opera 和 Microsoft Edge)中的工具,用于幫助開發人員調試和研究網站。

借助 Chrome DevTools,開發人員可以更深入地訪問網站,并能夠:

  • 檢查 DOM 中的元素

  • 即時編輯元素和 CSS

  • 檢查和監控網站的性能

  • 模擬用戶的地理位置

  • 模擬更快/更慢的網絡速度

  • 執行和調試 JavaScript

  • 查看控制臺日志

  • 等等

Selenium 4 Chrome DevTools API

圖片圖片

如果你想學習自動化測試,我這邊給你推薦一套視頻,這個視頻可以說是B站播放全網第一的接口自動化測試教程,同時在線人數到達1000人,并且還有筆記可以領取及各路大神技術交流:798478386? ???

【已更新】B站講的最詳細的Python接口自動化測試實戰教程全集(實戰最新版)_嗶哩嗶哩_bilibili【已更新】B站講的最詳細的Python接口自動化測試實戰教程全集(實戰最新版)共計200條視頻,包括:1.【接口自動化】目前軟件測試的市場行情以及測試人員能力標準。、2.【接口自動化】全面熟練Requests庫以及底層方法調用邏輯、3.【接口自動化】接口自動化實戰及正則和JsonPath提取器的應用等,UP主更多精彩視頻,請關注UP賬號。https://www.bilibili.com/video/BV17p4y1B77x/?spm_id_from=333.337&vd_source=488d25e59e6c5b111f7a1a1a16ecbe9a?

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" 首頁,如下圖所示。

圖片

借助像 Applitools Eyes 這樣的解決方案,我們不僅可以使用這些新的 Selenium 命令在不同的視口上快速進行測試,還可以在規模上保持任何不一致性。Eyes 足夠智能,不會對由于不同的瀏覽器和視口導致的 UI 中微小且難以察覺的變化報告錯誤的結果。

模擬地理位置

在許多情況下,我們需要測試特定的基于位置的功能,例如優惠、基于位置的價格等。為此,我們可以使用DevTools API來模擬位置。

  @Testpublic 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();}}

?

模擬網絡速度

許多用戶通過連接到 Wi-Fi 或蜂窩網絡的手持設備訪問 Web 應用程序。遇到信號弱的網絡信號,因此互聯網連接速度較慢是很常見的。

在互聯網連接速度較慢(2G)或間歇性斷網的情況下,測試應用程序在這種條件下的行為可能很重要。

偽造網絡連接的 CDP 命令是 Network.emulateNetworkConditions。關于此命令的必需和可選參數的信息可以在文檔中找到。

通過訪問 Chrome DevTools,就可以模擬這些場景。讓我們看看如何做到這一點。

package com.devtools;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.ConnectionType;import java.util.HashMap;
import java.util.Map;
import java.util.Optional;public class SetNetwork {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();devTools.send(Network.enable(Optional.empty(), Optional.empty(), Optional.empty()));devTools.send(Network.emulateNetworkConditions(false,20,20,50,Optional.of(ConnectionType.CELLULAR2G)));driver.get("https://www.google.com");}
}

在第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響應可用時觸發此事件,我們可以監聽URL、響應頭、響應代碼等。要獲取響應正文,請使用Network.getResponseBody方法。

 @Testpublic 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-5d63b2b2-3822-4a01-8197-acd8aa7e1343.php");}
}

在我們的代碼中,第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 NetworkDevTools chromeDevTools = driver.getDevTools();chromeDevTools.createSession();chromeDevTools.send(Network.enable(Optional.empty(), Optional.empty(), Optional.empty()));//Open websitedriver.get("https://jigsaw.w3.org/HTTP/");//Send authorization headerMap<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 unauthenticateddriver.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 中可能出現的任何其他功能!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/36261.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/36261.shtml
英文地址,請注明出處:http://en.pswp.cn/news/36261.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Observability:識別生成式 AI 搜索體驗中的慢速查詢

作者&#xff1a;Philipp Kahr Elasticsearch Service 用戶的重要注意事項&#xff1a;目前&#xff0c;本文中描述的 Kibana 設置更改僅限于 Cloud 控制臺&#xff0c;如果沒有我們支持團隊的手動干預&#xff0c;則無法進行配置。 我們的工程團隊正在努力消除對這些設置的限制…

uniapp動態底部tab欄

實現思路&#xff1a; 創建一個js文件用來存放所有的tabbar,不同的數組表示不同的tabbar組合。 創建一個vue文件用來制作底部tabbar組件。 使用vuex存儲用戶的身份信息,根據身份信息切換tabbar組合。 具體步驟&#xff1a; 新建一個tabbar.js文件&#xff0c;將…

SpringBoot 整合MyBatis

整合MyBatis 官方文檔&#xff1a;http://mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/ Maven倉庫地址&#xff1a;https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter/2.1.3 整合測試 導入 MyBatis 所需要的…

數據結構筆記--優先隊列(大小根堆)經典題型

1--項目的最大利潤 題目描述&#xff1a; 輸入&#xff1a;正數數組 costs&#xff0c;costs[i] 表示項目 i 的花費&#xff1b;正數數組 profits&#xff0c;profits[i] 表示項目 i 的花費&#xff1b;正數 k 表示只能串行完成最多 k 個項目&#xff1b;m 表示擁有的資金&…

MySQL事務:確保數據完整性與并發性的關鍵

MySQL事務&#xff1a;確保數據完整性與并發性的關鍵 MySQL作為一種廣泛使用的開源關系型數據庫管理系統&#xff0c;具備強大的事務支持&#xff0c;以確保數據庫操作的一致性、隔離性和持久性。本文將深入探討MySQL中的事務概念、事務隔離級別以及事務的應用場景&#xff0c…

leetcode 516. 最長回文子序列(JAVA)題解

題目鏈接https://leetcode.cn/problems/longest-palindromic-subsequence/description/?utm_sourceLCUS&utm_mediumip_redirect&utm_campaigntransfer2china 目錄 題目描述&#xff1a; 暴力遞歸&#xff1a; 動態規劃&#xff1a; 題目描述&#xff1a; 給你一個…

Python學習過程筆記:主模塊(main) 異常處理 命令行參數解析 日志記錄 socket模塊 類的私有方法 字節字符串

文章目錄 1.Python中的主程序2.Python中的異常處理3.Python中的命令行參數解析4.Python中的日志記錄5.網絡編程socket模塊6.Python中的私有方法7.Python中的字節字符串 1.Python中的主程序 if __name__ __main__在Python中&#xff0c;if __name__ __main__ 是一個常見的代碼…

百日筑基篇——python爬蟲學習(一)

百日筑基篇——python爬蟲學習&#xff08;一&#xff09; 文章目錄 前言一、python爬蟲介紹二、URL管理器三、所需基礎模塊的介紹1. requests2. BeautifulSoup1. HTML介紹2. 網頁解析器 四、實操1. 代碼展示2. 代碼解釋1. 將大文件劃分為小的文件&#xff08;根據AA的ID數量劃…

簡單認識Zabbix監控系統及配置

文章目錄 一、zabbix概述1、定義2、zabbix監控原理3、監控對象4、zabbix的3種架構&#xff08;1&#xff09; C/S架構&#xff08;2&#xff09;分布式架構&#xff1a;zabbix-proxy-client架構&#xff08;3&#xff09; master-node-client架構 5、zabbix監控模式 二、部署za…

項目實戰 — 消息隊列(8){網絡通信設計①}

目錄 一、自定義應用層協議 &#x1f345; 1、格式定義 &#x1f345; 2、準備工作 &#x1f384;定義請求和響應 &#x1f384; 定義BasicArguments &#x1f384; 定義BasicReturns &#x1f345; 2、創建參數類 &#x1f384; 交換機 &#x1f384; 隊列 &#x1f38…

【網絡】傳輸層——TCP(滑動窗口流量控制擁塞控制延遲應答捎帶應答)

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;專欄&#xff1a;《網絡》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交給時間&#xff01; 上篇文章對TCP可靠性機制講解了一部分&#xff0c;這篇文章接著繼續講解。 &#x1f3a8;滑動窗口 在…

Springboot 實踐(2)MyEclipse2019創建項目修改pom文件,加載springboot 及swagger-ui jar包

MyEclipse2019創建工程之后&#xff0c;需要添加Springboot啟動函數、添加application.yml配置文件、修改pom文件添加項目使用的jar包。 添加Springboot啟動函數 創建文件存儲路徑 &#xff08;1&#xff09;右鍵單擊“src/main/java”文件夾&#xff0c;彈出對話框輸入路徑…

Android 簡單的視頻、圖片壓縮工具

首頁需要壓縮的工具包 1.Gradle implementation com.iceteck.silicompressorr:silicompressor:2.2.3 2.添加相關權限&#xff08;手機得動態申請權限&#xff09; <uses-permission android:name"android.permission.READ_EXTERNAL_STORAGE"/> <uses-p…

05 - 研究 .git 目錄

查看所有文章鏈接&#xff1a;&#xff08;更新中&#xff09;GIT常用場景- 目錄 文章目錄 1. HEAD2. config3. refs4. objects 1. HEAD 2. config 3. refs 4. objects Git對象一共有三種&#xff1a;數據對象 blob、樹對象 tree以及提交對象 commit&#xff0c;這些對象都被保…

Vue 目錄結構 vite 項目

Vue3 項目常用的目錄結構和每個文件的作用【通過 vite 創建的項目】 vite目錄結構&#xff1a; dist // 打包后生成的文件目錄 node_modules // 環境依賴 public // 公共資源目錄 favicon.ico …

深入探析設計模式:工廠模式的三種姿態

深入探析設計模式&#xff1a;工廠模式的三種姿態 1. 簡單工廠模式1.1 概念1.2 案例1.3 優缺點 2. 抽象工廠模式2.1 概念2.2 案例&#xff1a;跨品牌手機生產2.3 優缺點 3. 超級工廠模式3.1 概念3.2 案例&#xff1a;動物園游覽3.3 優缺點 4. 總結 歡迎閱讀本文&#xff0c;今天…

go入門實踐四-go實現一個簡單的tcp-socks5代理服務

文章目錄 前言socks協議簡介go實現一個簡單的socks5代理運行與壓測抓包驗證 前言 SOCKS是一種網絡傳輸協議&#xff0c;主要用于客戶端與外網服務器之間通訊的中間傳遞。協議在應用層和傳輸層之間。 本文使用先了解socks協議。然后實現一個socks5的tcp代理服務端。最后&#…

英語詞法——代詞

代詞是用來代替名詞、起名詞作用的短語、分句和句子的詞。英語中代詞根據其意義和作用可分為九類:人稱代詞、物主代詞、反身代詞、相互代詞、指示代詞、疑問代詞、不定代詞、關系代詞和連接代詞。 第一節 人稱代詞 一、人稱代詞的形式和用法 人稱代詞單數復數第一人稱第二人…

【ARM 嵌入式 編譯系列 4 -- GCC 編譯屬性 __read_mostly 詳細介紹】

文章目錄 __read_mostly 介紹__read_mostly 在 linux 中的使用.data.read_mostly 介紹 __read_mostly 介紹 __read_mostly 是一個在Linux內核編程中用到的宏定義&#xff0c;這是一個gcc編譯器的屬性&#xff0c;用于告訴編譯器此變量主要用于讀取&#xff0c;很少進行寫入&am…

MYSQL中用字符串2022-07去匹配Date類型大于2022-07-01并小于2022-07-31

正文 需求上&#xff0c;是有個日期字符串&#xff0c;例如2022-07&#xff0c;代表著年月。數據庫中表對于這個字段存的是年月日&#xff0c;例如&#xff1a;2022-07-15。 我希望的是&#xff1a;獲取到2022-07-01到2022-07-31&#xff0c;之間的數據&#xff0c;條件是&…