软件测试—— Selenium 常用函数(一)

前一篇文章:软件测试 —— 自动化基础-CSDN博客

目录

·前言

一、窗口

1.屏幕截图

2.切换窗口

3.窗口设置大小

4.关闭窗口

二、等待

1.等待意义

2.强制等待

3.隐式等待

4.显式等待

·总结


·前言

        在前一篇文章中,我们介绍了自动化的一些基础知识,还介绍及简单使用了 Selenium 这个 Web 自动化测试工具及部分函数,本篇文章来对 Selenium 里的常用函数继续进行介绍,这里介绍的函数主要是对浏览器窗口与等待方式的常见操作进行自动化,下面就开始本篇文章的内容介绍吧。

一、窗口

1.屏幕截图

        在介绍屏幕截图前,先给大家演示一段代码示例,这里的代码及详细介绍和运行效果如下所示:

public class Test {WebDriver driver;// 创建驱动void createDriver() {// 1. 创建驱动对象, 打开浏览器WebDriverManager.chromedriver().setup();// 2. 增加浏览器配置, 创建驱动对象要强制指定允许访问所有链接ChromeOptions options = new ChromeOptions();options.addArguments("--remote-allow-origins=*");driver = new ChromeDriver(options);// 3. 输入完整的网址: https:www.baidu.comdriver.get("https://www.baidu.com/");}void test05() throws IOException, InterruptedException {createDriver();// 查找元素并进行点击, 这里查找的是 "百度首页" 中的 "新闻"driver.findElement(By.cssSelector("#s-top-left > a:nth-child(1)")).click();// 观察结果Thread.sleep(3000);// 使用 element 获取查找的元素WebElement element = driver.findElement(By.cssSelector("#news-hotwords > div.bd > ul > li.li_0.li_color_0.button-slide > a"));// 打印元素的文本信息System.out.println(element.getText());driver.quit();}public static void main(String[] args) throws InterruptedException, IOException {Test test = new Test();test.test05();}
}

        此时代码出现了报错,我们把跳转后要查找的元素选择器的值在相应页面进行查找,如下图所示: 

        既然跳转后的网站可以查找到对应元素,为什么运行程序后会报错呢?此时我们就可以通过屏幕截图来抓拍程序运行时的错误场景。

        使用屏幕截图方法需要添加相应的依赖,添加依赖代码如下所示:

        <dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.6</version></dependency>

        添加完依赖之后,我们就可以编写一个简单的屏幕截图代码,添加到上述代码中,来观察结果,代码及详细介绍如下所示: 

    void test05() throws IOException, InterruptedException {createDriver();// 查找元素并进行点击, 这里查找的是 "百度首页" 中的 "新闻"driver.findElement(By.cssSelector("#s-top-left > a:nth-child(1)")).click();// 观察结果Thread.sleep(3000);// 屏幕截图File srcFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);// 把截图 srcFile 放到指定的位置FileUtils.copyFile(srcFile, new File("my.png"));// 使用 element 获取查找的元素WebElement element = driver.findElement(By.cssSelector("#news-hotwords > div.bd > ul > li.li_0.li_color_0.button-slide > a"));// 打印元素的文本信息System.out.println(element.getText());driver.quit();}

        此时,我们屏幕截取的图片如下所示: 

        通过观察屏幕截图抓拍程序运行时的图片可以发现,程序在点击“新闻”这个标签后,并不像我们眼睛所观察的结果一样跳转到了“新闻”这个标签页,而是还停留在百度首页,所以才会出现错误,查找不到元素的情况。

        如何解决这个问题,我们留到下面“切换窗口”来介绍,下面我来对屏幕截图再做一些介绍,刚才我们在代码中使用的屏幕截图是最简单的版本,它会出现一个严重的问题,就是如果多次调用这种方式来截图,那么之后只能获取最后一次屏幕截图的图片,其余都会被覆盖,我们在使用屏幕截图一定要注意以下几点:

  • 每次生成的屏幕截图都能保存下来,避免覆盖;
  • 屏幕截图文件同一放在一个文件夹下(如:image);
  • 生成的屏幕截图名称要见名知意,即一看见这个屏幕截图就知道是什么时候的。 

        下面我来规划一下生成屏幕截图文件夹的结构,如下图所示:         规定好生成屏幕截图的文件存储方式后,我们就实现一个方法来专门处理屏幕截图的操作,方法的具体代码及详细介绍如下所示:

    // 进阶版屏幕截图void getScreenShot(String str) throws IOException {// 规定时间格式为 年-月-日, 如: 2024-11-17SimpleDateFormat sim1 = new SimpleDateFormat("yyyy-MM-dd");// 规定时间格式为 时分秒毫秒, 如: 171953345SimpleDateFormat sim2 = new SimpleDateFormat("HHmmssSS");// 创建文件夹的名称, 以现在的日期来命名, 用 sim1 来转化时间格式String dirTime = sim1.format(System.currentTimeMillis());// 创建文件名称, 以现在的时间来命名, 用 sim2 来转化时间格式String fileTime = sim2.format(System.currentTimeMillis());// 拼接好完整文件名(包含:存放具体位置,及文件名称)String filename = "./src/test/image/" + dirTime + "/" + str + "-" + fileTime + ".png";// 打印完整文件名,用来调试System.out.println("filename: " + filename);// 屏幕截图File srcFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);// 把截图 srcFile 放到指定的位置FileUtils.copyFile(srcFile, new File(filename));}

2.切换窗口

        通过上面屏幕截图的示例,我们会发现,在百度首页点击“新闻”时会新打开一个标签页,然而我们的 driver 还停留在前一个页面,这就导致我想获取新的页面中的元素获取不到,这是因为,在我们手工测试的时候可以通过眼睛来判断当前的窗口是什么,但是对应程序来说,它无法判断当前最新的窗口应该是哪一个,那么程序如何来识别每一个窗口呢?其实我们浏览器的每个窗口都有一个唯一的属性句柄(handle),我们可以通过句柄来切换我们当前的浏览器窗口。

        介绍完这些,我们就可以在代码中进行切换窗口的操作了,我们来对上面的错误代码进行修改,具体代码及详细介绍和运行结果如下所示:

    // 切换窗口void test05() throws IOException, InterruptedException {// 创建驱动createDriver();// 屏幕截图getScreenShot("test05()");// 查找元素并进行点击, 这里查找的是 "百度首页" 中的 "新闻"driver.findElement(By.cssSelector("#s-top-left > a:nth-child(1)")).click();// 获取当前的句柄String curHandle = driver.getWindowHandle();// 接收当前所有句柄Set<String> allHandles = driver.getWindowHandles();// 遍历获取到非当前句柄的句柄for (String handle : allHandles) {if (!handle.equals(curHandle)) {// 切换句柄 driver--->百度新闻driver.switchTo().window(handle);}}// 屏幕截图getScreenShot("test05");// 使用 element 获取查找的元素WebElement element = driver.findElement(By.cssSelector("#news-hotwords > div.bd > ul > li.li_0.li_color_0.button-slide > a"));// 打印元素的文本信息System.out.println(element.getText());driver.quit();}

        执行过程中的两次屏幕截图如下所示:

        到这,窗口的切换就介绍完了。 

3.窗口设置大小

        窗口的大小设置有以下四种情况:

  • 窗口最大化;
  • 窗口最小化;
  • 窗口全屏;
  • 手动设置窗口大小。

        对于这四种窗口大小的设置方式,Selenium 中也有对应的函数来实现,下面我就来编写代码演示一下这四个函数的用法及效果,具体代码及详细介绍如下所示:

public class Test {WebDriver driver;// 创建驱动void createDriver() {// 1. 创建驱动对象, 打开浏览器WebDriverManager.chromedriver().setup();// 2. 增加浏览器配置, 创建驱动对象要强制指定允许访问所有链接ChromeOptions options = new ChromeOptions();options.addArguments("--remote-allow-origins=*");driver = new ChromeDriver(options);// 3. 输入完整的网址: https:www.baidu.comdriver.get("https://www.baidu.com/");}// 设置窗口大小void test06() throws InterruptedException {// 创建驱动createDriver();Thread.sleep(2000);// 窗口最大化driver.manage().window().maximize();Thread.sleep(2000);// 窗口最小化driver.manage().window().minimize();Thread.sleep(2000);// 全屏窗口driver.manage().window().fullscreen();Thread.sleep(2000);// 手动设置窗口大小driver.manage().window().setSize(new Dimension(700,521));Thread.sleep(2000);driver.quit();}public static void main(String[] args) throws InterruptedException, IOException {Test test = new Test();test.test06();}
}

​​​​​​​

4.关闭窗口

        关闭窗口之后要注意 driver 要重新定义,当 driver 调用关闭窗口的函数之后,driver 所在的就是一个空的窗口了,此时使用 driver 进行的所有操作就都会报错,所以需要在关闭窗口后对 driver 进行重新定义,函数的具体使用方式如下:

// 关闭当前窗口
driver.close();

二、等待

1.等待意义

        我们来观察一段代码示例的运行结果,这里的代码及详细介绍和运行效果如下所示:

public class Test {WebDriver driver;// 创建驱动void createDriver() {// 1. 创建驱动对象, 打开浏览器WebDriverManager.chromedriver().setup();// 2. 增加浏览器配置, 创建驱动对象要强制指定允许访问所有链接ChromeOptions options = new ChromeOptions();options.addArguments("--remote-allow-origins=*");driver = new ChromeDriver(options);// 3. 输入完整的网址: https:www.baidu.comdriver.get("https://www.baidu.com/");}void test07() {// 创建驱动createDriver();// 查找搜索框, 输入 "彭于晏"driver.findElement(By.cssSelector("#kw")).sendKeys("彭于晏");// 查找 "百度一下" 按钮, 点击搜索driver.findElement(By.cssSelector("#su")).click();// 在跳转后的页面查找 "百度百科" 的元素位置driver.findElement(By.cssSelector("#\\31  > div > div > div > div > div > div.new-tag_4ozgi.new-text-link_3k9GD > div > div.flex-wrapper-top_3ucFS > div.flex-col-left_3trtY.baike-wrapper_6AORN.cu-pt-xs-lg.baike-wrapper-pc_26R04.cu-pt-xl.baike-wrapper-left-pc_5eYY8.cos-space-pb-sm > div > div > p > span:nth-child(1) > span"));driver.quit();}public static void main(String[] args) throws InterruptedException, IOException {Test test = new Test();test.test07();}}

        此时代码出现了报错,我们把跳转后要查找的元素选择器的值在相应页面进行查找,如下图所示:

        既然跳转后的网站可以查找到对应元素,为什么运行程序后会报错呢?此时我们就可以通过屏幕截图来抓拍程序运行时的错误场景,截取的页面如下所示:

        根据截取的图片我们会发现,在点击“百度一下”之后,跳转的页面还没有把我们要获取的元素渲染出来,所以导致了我们查找元素失败的结果, 此时我们在报错的代码前加上 Thread.sleep(秒),设置时间长一点就可以获取到查找的元素了。

        我们使用等待,就是为了预防由于代码执行速度比页面渲染速度快导致页面没有渲染出来,程序就已经开始查找元素使元素没有被找到的问题,在 Selenium 中,为我们提供了三种等待方法:强制等待、隐式等待、显示等待。

2.强制等待

        强制等待对我们来说已经是非常熟悉了,它使用的就是 Thread.sleep() 这个方法,前面使用的地方有很多,这里就不再进行演示了,关于强制等待,它的优缺点如下:

  • 优点:使用简单,调试的时候比较有效;
  • 缺点:影响运行效率,浪费大量的时间。

        对于强制等待这种方式主要应用的场景就是在我们调试代码期间。 

3.隐式等待

        隐式等待是一种智能等待,它可以规定在查找元素时,在指定时间内不断查找元素,如果找到则代码继续执行,如果直到超时还没找到元素就会报错。下面我在上面代码中进行使用隐式等待,具体代码及运行结果如下所示:

public class Test {WebDriver driver;// 创建驱动void createDriver() {// 1. 创建驱动对象, 打开浏览器WebDriverManager.chromedriver().setup();// 2. 增加浏览器配置, 创建驱动对象要强制指定允许访问所有链接ChromeOptions options = new ChromeOptions();options.addArguments("--remote-allow-origins=*");driver = new ChromeDriver(options);// 3. 输入完整的网址: https:www.baidu.comdriver.get("https://www.baidu.com/");}void test07() {// 创建驱动createDriver();// 加入隐式等待, 超时时间为 3 秒driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(3));// 查找搜索框, 输入 "彭于晏"driver.findElement(By.cssSelector("#kw")).sendKeys("彭于晏");// 查找 "百度一下" 按钮, 点击搜索driver.findElement(By.cssSelector("#su")).click();// 点击搜索之后,进行 "屏幕截图"getScreenShot("test07");// 在跳转后的页面查找 "百度百科" 的元素位置driver.findElement(By.cssSelector("#\\31  > div > div > div > div > div > div.new-tag_4ozgi.new-text-link_3k9GD > div > div.flex-wrapper-top_3ucFS > div.flex-col-left_3trtY.baike-wrapper_6AORN.cu-pt-xs-lg.baike-wrapper-pc_26R04.cu-pt-xl.baike-wrapper-left-pc_5eYY8.cos-space-pb-sm > div > div > p > span:nth-child(1) > span"));driver.quit();}public static void main(String[] args) throws InterruptedException, IOException {Test test = new Test();test.test07();}}

         此时,程序就可以正确的找到元素了。

        隐式等待用到的方法是 implicitlyWait(),参数:Duration 类中提供的毫秒、秒、分钟等方法,隐式等待的作用域是整个脚本的所有元素,只要 driver 对象没有被释放掉(driver.quit()),隐式等待就会一直生效,有关隐式等待的优缺点如下:

  • 优点:智能等待,作用于全局;
  • 缺点:只能查找元素时才会触发。

4.显式等待

        显式等待也是一种智能等待,在指定超时时间范围内只要满足操作条件就会继续执行后续代码,它的使用代码如下所示:

new WebDriverWait(driver, Duration.ofSeconds(3)).until($express)

        这里的 $express:涉及到 Selenium.support.ui.ExpectedConditions 包下的 ExpectedConditions 类,在这个类中包含了许多方法,如下图所示:        这里我来简单介绍其中几个方法,如下表所示:

方法作用
elementToBeClickable(By locator)用于检查元素的期望是可见的并已启用,以便我们可以点击它。
textToBe(By locator, String str)检查元素是否存在(精确匹配)。
presenceOfElementLocated(By locator)检查页面的 DOM 上是否存在元素。
urlToBe(String url)检查当前页面的 URL 是一个特定的 URL

        下面我来编写一段显式等待的使用代码,具体代码及结果如下所示:

public class Test {WebDriver driver;// 创建驱动void createDriver() {// 1. 创建驱动对象, 打开浏览器WebDriverManager.chromedriver().setup();// 2. 增加浏览器配置, 创建驱动对象要强制指定允许访问所有链接ChromeOptions options = new ChromeOptions();options.addArguments("--remote-allow-origins=*");driver = new ChromeDriver(options);// 3. 输入完整的网址: https:www.baidu.comdriver.get("https://www.baidu.com/");}// 测试显示等待void test08() {createDriver();// 连续写法// new WebDriverWait(driver, Duration.ofSeconds(3)).until(ExpectedConditions.elementToBeClickable(By.cssSelector("#su")));// 分开写法WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(3));// 百度输入框是否存在wait.until(ExpectedConditions.elementToBeClickable(By.cssSelector("#kw")));driver.findElement(By.cssSelector("#kw"));driver.quit();}public static void main(String[] args) throws InterruptedException, IOException {Test test = new Test();test.test08();}
}

        此时程序正确运行, 

        显式等待只作用在当前的条件上,有关显式等待的优缺点如下:

  • 优点:显式等待是智能等待,可以自定义显示等待的条件,操作灵活;
  • 缺点:写法复杂。 

        如果显式等待和隐式等待一起使用效果会如何呢?我们可以再编写一段代码来观察其运行结果,具体代码及运行结果如下所示:

public class Test {WebDriver driver;// 创建驱动void createDriver() {// 1. 创建驱动对象, 打开浏览器WebDriverManager.chromedriver().setup();// 2. 增加浏览器配置, 创建驱动对象要强制指定允许访问所有链接ChromeOptions options = new ChromeOptions();options.addArguments("--remote-allow-origins=*");driver = new ChromeDriver(options);// 3. 输入完整的网址: https:www.baidu.comdriver.get("https://www.baidu.com/");}// 测试显式等待与隐式等待一起使用void test09() {createDriver();//隐式等待设置为5s,显式等待设置为10s,那么结果会是等待多少?SimpleDateFormat sim =new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");// 打印运行之前时间System.out.println(sim.format(System.currentTimeMillis()));// 设置隐式等待driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5));// 设置显式等待WebDriverWait wait = new WebDriverWait(driver,Duration.ofSeconds(10));try {// 查找的元素不存在wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("#iiiii")));}catch (Exception e) {System.out.println("没有找到元素!");}// 打印运行结束后的时间System.out.println(sim.format(System.currentTimeMillis()));driver.quit();}public static void main(String[] args) throws InterruptedException, IOException {Test test = new Test();test.test09();}
}

        经过多次次运行,打印的等待时间有 10s 与 11s,由此我们可以看出,在混合使用隐式等待和显式等待时,可能会导致不可预测的等待时间。

·总结

        文章到此就要结束了,本篇文章介绍了使用 Selenium 中函数来对浏览器中窗口各种操作的自动化实现,以及介绍了等待这一操作的作用及相关用法,如果对文章内容有所疑惑,欢迎在评论区进行留言,如果感觉本篇文章还不错希望能收到你的三连支持,那么我们下一篇文章再见吧~~~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/475623.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Rust 力扣 - 746. 使用最小花费爬楼梯

文章目录 题目描述题解思路题解代码题目链接 题目描述 题解思路 我们使用a&#xff0c;b分别记录n - 2层向上爬的最小花费&#xff0c;n - 1层向上爬的最小花费 到达楼梯顶第N层&#xff0c;只能从N - 1层或者N - 2层向上爬 所以爬到第N层的最小花费 第N - 1层向上爬和第N - …

VRT: 关于视频修复的模型

VRT: 关于视频修复的模型 1. 视频修复的背景与重要性背景介绍&#xff1a;重要性&#xff1a; 2. VRT的重要性和研究背景VRT的背景&#xff1a;VRT的重要性&#xff1a; 3. 视频修复概述3.1 定义与目标3.2 与单图像修复的区别3.3 对时间信息利用的需求 4. VRT模型详解4.1 整体框…

关于C++地址交换的实现

关于地址的交换实现&#xff0c;我们要使用指针引用的方式进行&#xff0c;例如&#xff1a; #include <iostream>// 定义函数交换两个整型指针的地址 void swapIntPtrAddresses(int* &ptr1, int* &ptr2) {int *temp ptr1;ptr1 ptr2;ptr2 temp; }int main() …

HarmonyOS ArkUI(基于ArkTS) 常用组件

一 Button 按钮 Button是按钮组件&#xff0c;通常用于响应用户的点击操作,可以加子组件 Button(我是button)Button(){Text(我是button)}type 按钮类型 Button有三种可选类型&#xff0c;分别为胶囊类型&#xff08;Capsule&#xff09;、圆形按钮&#xff08;Circle&#xf…

SpringBoot学习笔记(一)

一、Spring Boot概述 &#xff08;一&#xff09;微服务概述 1、微服务 微服务&#xff08;英语&#xff1a;Microservices&#xff09;是一种软件架构风格&#xff0c;它是以专注于单一责任与功能的小型功能区块 (Small Building Blocks) 为基础&#xff0c;利用模块化的方式…

C++初阶(十三)--STL--vector的使用

目录 ​编辑 一、vector的基本介绍 二、vector的使用 1.构造函数的介绍 2.容量操作 size和capacity reserve和resize empty 3.vector的遍历 operator[ ](size_t n) 迭代器使用 begin和end rbegin和rend 4.vector的增删查改 push_back和pop_back insert和erase fi…

用Python爬虫“偷窥”1688商品详情:一场数据的奇妙冒险

引言&#xff1a;数据的宝藏 在这个信息爆炸的时代&#xff0c;数据就像是一座座等待挖掘的宝藏。而对于我们这些电商界的探险家来说&#xff0c;1688上的商品详情就是那些闪闪发光的金子。今天&#xff0c;我们将化身为数据的海盗&#xff0c;用Python这把锋利的剑&#xff0…

matlab的函数名和函数文件名的关系(编程注意事项)

在MATLAB中&#xff0c;函数名和函数文件名之间有着重要的关系。以下是它们之间的关系以及在编程时需要注意的事项 文章目录 函数名与函数文件名的关系编程时的注意事项结论 函数名与函数文件名的关系 一致性要求&#xff1a; 在MATLAB中&#xff0c;函数文件的文件名必须与函数…

【Redis】持久化机制RDB与AOF

一、RDB RDB模式是就是将内存中的数据存储到磁盘中&#xff0c;等到连接断开的时候会进行持久化操作。但是如果服务器宕机&#xff0c;会导致这个持久化机制不会执行&#xff0c;但是内存中的文件会直接丢失。所以可以设置一个触发机制&#xff0c;save 60 1000 就是代表60秒 执…

基于Lora通讯加STM32空气质量检测WIFI通讯-分享

目录 目录 前言 一、本设计主要实现哪些很“开门”功能&#xff1f; 二、电路设计原理图 1.电路图采用Altium Designer进行设计&#xff1a; 2.实物展示图片 三、程序源代码设计 四、获取资料内容 前言 随着环境污染问题的日益严重&#xff0c;空气质量的监测与管理已经…

【MySQL】ubantu 系统 MySQL的安装与免密码登录的配置

&#x1f351;个人主页&#xff1a;Jupiter. &#x1f680; 所属专栏&#xff1a;MySQL初阶探索&#xff1a;构建数据库基础 欢迎大家点赞收藏评论&#x1f60a; 目录 &#x1f4da;mysql的安装&#x1f4d5;MySQL的登录&#x1f30f;MySQL配置免密码登录 &#x1f4da;mysql的…

【STK学习】part2-星座-目标可见性与覆盖性分析

【Satellite Tool Kit】学习并深入了解卫星/星座生成、可见性分析、覆盖性分析等知识&#xff0c;并基于STK软件实现对应数据的导出&#xff0c;以用于算法的约束输入。 文章目录 一、学习目标二、学习内容2.1 星地可见性分析2.1.1 单星单地2.1.2 单星多地2.1.3 多星单地 2.2 星…

框架实战:SSM整合原理和实战

1. SSM整合理解 1.1. IOC两个容器对应组件 容器名盛放组件web容器web相关组件&#xff08;controller,springmvc核心组件&#xff09;root容器业务和持久层相关组件&#xff08;service,aop,tx,dataSource,mybatis,mapper等&#xff09; 配置文件 配置名对应内容对应容器Web…

自然语言处理:第六十三章 阿里Qwen2 2.5系列

本人项目地址大全&#xff1a;Victor94-king/NLP__ManVictor: CSDN of ManVictor 项目地址: QwenLM/Qwen2.5: Qwen2.5 is the large language model series developed by Qwen team, Alibaba Cloud. 官网地址: 你好&#xff0c;Qwen2 | Qwen & Qwen2.5: 基础模型大派对&a…

i春秋-登陆(sql盲注爆字段,.git缓存利用)

练习平台地址 竞赛中心 题目描述 先登陆再说 题目内容 就是一个登录框 测试登录 用户名&#xff1a;admin or 11# 密码&#xff1a;随便输 返回密码错误 用户名&#xff1a;随便输 密码&#xff1a;随便输 返回用户名不存在 这里就可以确定时一个bool盲注了 这里提供一个lik…

新华三H3CNE网络工程师认证—子接口技术

子接口&#xff08;subinterface&#xff09;是通过协议和技术将一个物理接口&#xff08;interface&#xff09;虚拟出来的多个逻辑接口。在VLAN虚拟局域网中&#xff0c;通常是一个物理接口对应一个 VLAN。在多个 VLAN 的网络上&#xff0c;无法使用单台路由器的一个物理接口…

C# - 无法加载 DLL“libmupdf.dll”: 找不到指定的模块。

1.本机环境 windows 11 64位Visual Studio 2015 2.报错如下 用户代码未处理 System.DllNotFoundException HResult-2146233052 Message无法加载 DLL“libmupdf.dll”: 找不到指定的模块。 (异常来自 HRESULT:0x8007007E)。 SourceMoonPdfLib TypeName"" StackTrac…

23.UE5删除存档

2-25 删除存档制作_哔哩哔哩_bilibili 按照自己的风格制作删除按钮 这样该行的存档就被从存档列表中删除了&#xff0c;并且实际存档&#xff08;我的存档蓝图&#xff09;中也被删除了 但是存在一个问题&#xff0c;如果存档数据中存在索引为: 0 1 2 3的存档&#xff0c;当索…

VSCode DeBug时无法进入自定义工具库

最近遇到一个问题&#xff0c;将自己的写的工具包放到conda里site-packagse下&#xff0c;并配置了__init__.py文件&#xff0c;当我debug时&#xff0c;想进入工具包函数调试&#xff0c;但是总是进入不了工具包函数。找了许多博客方法&#xff0c;尝试了将launch.json中的jus…

单元测试框架gtest学习(三)—— 事件机制

前言 上节我们学习了gtest的各种宏断言 单元测试框架gtest学习&#xff08;二&#xff09;—— 认识断言-CSDN博客 本节我们介绍gtets的事件机制 虽然 Google Test 的核心是用来编写单元测试和断言的&#xff0c;但它也允许在测试执行过程中进行事件的钩取和自定义&#xf…