介绍:本篇旨在学习自动化测试,使用的语言为Java。因为需要使用到自动化测试相关的非内置包体,所以创建的类型均为Maven项目,用pom.xml来下载所需自动化相关包体。
概念:自动化的主要目的就是用来进行回归测试。
什么是回归测试?
我们常见的大多数软件都是有多个版本的。软件生产厂商对于版本的更新迭代的过程是在原有的功能基础上添加新的功能或者优化旧的模块。
而测试工程师对于软件的测试工作是伴随着软件的整个生命周期的。
例如:我们常见的微信,QQ就有着多个版本,不同版本对设备的硬件配置和系统配置的适应性兼容性不同,它们在版本的小迭代的软件优化上是不会出现因为小更新而导致之前版本都无法使用的这种情况。
因此,测试工程师在每一次版本的迭代上都需要对软件进行测试。但是软件的版本不断迭代优化,在保证新增的功能没有问题的情况下,还要同时保证旧的功能可以正常使用的,而对于历史功能的测试就是回归测试。
一、自动化
介绍:自动化在我们的生活中处处可见,如设定温度后会自动保持恒定温度的空调,超市里根据感应自动打开关闭的闸门,农田内自主灌溉的喷水器,小米自动化工厂的生产车间。
软件中的自动化也是如此,通过提前的设定配置,让程序通过自动化测试来有效减少测试人员的人力消耗,同时也可以提高工作效率和工作质量。
自动化分类:
| 层级 | 测试对象 |
|---|---|
| 单元测试(底层) | 单个函数、类、方法 |
| 接口/服务测试(中层) | API、微服务间的交互 |
| UI端到端测试(顶层) | 模拟用户在浏览器/App的操作 |
上述表格中的层级是以软件与人的距离来划分的,最顶层的就是用户可以看见的就是前端的界面,越往下走对于用户来说越远。
而对于UI的测试又分为多种,移动端测试,Web测试。
①.移动端测试
移动端测试通常不是将程序部署在移动端上进行测试,而是需要安装模拟器,在电脑上编写自动化测试脚本代码对模拟器上的软件进行操作。
移动端测试难度相对较大,移动端测试的稳定性要比接口自动化测试和web自动化测试的稳定性要差很多,原因主要是移动端测试受到的环境影响比较多。
②.Web测试
Web测试则是像我们自己动手打开网页进行测试一样,而让程序操控网页模拟人来操作的行为就是Web自动化测试。
二、Web自动化准备
前提知识与排错:
1)Xpath和selector:
Xpath和selector是比较常用的用于定位网页标签的元素。
如何查看Web页面选项的表达式?
①.打开网页,启动开发者工具(快捷键:F12),开启功能按钮,通过鼠标定位到页面元素
②.右击对应元素,选择copy,复制相应表达式
2)准备过程可能出现的问题:
①.dependency标签标红显示
Maven 规定:<dependency>标签必须放在<dependencies>这个父标签内部,而不能直接放在<project>下面,也不能放在<build>、<properties>等其他标签下面。
②.标签里的内容标红显示
没有刷新 Maven:
1)右击鼠标,打开属性面板刷新
2)看 IDEA 右侧边栏的Maven选项卡,点击左上角的刷新图标
③.依赖正确安装,代码正确,运行错误
可能是浏览器下载错误,比如下载了盗版的浏览器。
1.Web驱动管理
驱动管理: WebDriverManager是一个开源Java库,以完全自动化的方式对Selenium WebDriver所需的驱动程序(如chromedriver、geckodriver、msedgedriver等)进行管理(即下载、设置和维护),自版本5起,WebDriverManager还提供了其他相关功能,如发现本地系统中安装的浏览器的能力,构建WebDriver对象(如ChromeDriver、FirefoxDriver、EdgeDriver等)
1)安装Web驱动管理
①.自动化安装(推荐)
添加依赖:在的pom.xml(Maven)或build.gradle(Gradle)文件中添加依赖
<dependency> <groupId>io.github.bonigarcia</groupId> <artifactId>webdrivermanager</artifactId> <version>5.8.0</version> <scope>test</scope> </dependency>备注:<scope>test</scope>会将依赖的作用域限制在项目的Test文件夹下(在其他文件夹下不识别不到是无法补全引用该依赖的),可以将其去掉,它只是一种规范,不会影响到日常的使用。
注意:其中对于<version>标签内的版本,可根据需求自行调整。
②.手动安装
下载链接:Unable to Locate Driver Error | Selenium
根据不同的浏览器下载不同的驱动即可。
缺点:浏览器默认会自动更新,每隔一段时间需重新下载,否则会出现驱动版本不匹配而无法正常运行自动化,所以不推荐使用手动下载。
2)代码示例
//1.成功下载Web驱动管理包体到本地后,可以直接通过 WebDriverManager 方法来下载常用浏览器对应的驱动 //2.自动处理 ChromeDriver(并不是只能下载谷歌的) 的下载和配置 //3.再通过 setup() 方法载入 WebDriverManager.chromedriver().setup();笔记:当setup()被调用时,WebDriverManager会在后台执行一系列操作:检查系统、发现浏览器版本、解析正确的驱动版本、下载并缓存驱动、最后设置好系统属性。
2.Selenium
介绍:selenium是⼀个web自动化测试工具,selenium中提供了丰富的方法供给使用者进行web自动化测试。
1)安装Selenium库
添加依赖:在的pom.xml(Maven)或build.gradle(Gradle)文件中添加依赖
<dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-java</artifactId> <version>4.0.0</version> </dependency>2)Seleunim官方文档
文档链接:Overview
3)代码示例
// 创建 WebDriver 实例 WebDriver driver = new ChromeDriver(); //通过实例的 get("网址链接") 方法来指定打开资源链接 driver.get("https://www.example.com"); // ... //释放资源,相当于关闭网页(保持良好的习惯) driver.quit();3.综合测试示例
通过Java代码模拟人的行为,操作步骤:打开浏览器,输入百度网址并打开,找到输入框并输入“淘宝”,找到百度一下按钮并点击,退出浏览器。
package autoTest; import io.github.bonigarcia.wdm.WebDriverManager; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.chrome.ChromeOptions; public class TestChrome { public void chrome_example_test(){ //驱动程序管理的自动化 WebDriverManager.chromedriver().setup(); ChromeOptions options=new ChromeOptions(); //允许访问所有链接 options.addArguments("--remote-allow-origins=*"); //1.打开浏览器 WebDriver driver=new ChromeDriver(options); //2.输入百度网址:https://www.baidu.com driver.get("https://www.baidu.com"); //3.找到输入框并输入“淘宝” driver.findElement(By.xpath("//*[@id=\"kw\"]")).sendKeys("淘宝"); //4.找到”百度一下“的按钮并点击 driver.findElement(By.xpath("//*[@id=\"kw\"]")).click(); //5.关闭浏览器 driver.quit(); } }注意:
options.addArguments("--remote-allow-origins=*"); 是启动选项配置。
拆解:
options:指的是 Chrome 浏览器的启动配置对象(ChromeOptions)。addArguments:添加 Chrome 浏览器的启动命令行参数。--remote-allow-origins=*:告诉 Chrome,允许来自任何域(*)的远程调试/控制请求连接到这个浏览器实例。
三、Web自动化方法
1.元素的定位
介绍:web自动化测试的操作核心是能够找到页面对应的元素,然后才能对元素进行具体的操作。常见元素定位方式非常多,如id,classname,tagname,xpath,cssSelector。常用的主要是cssSelector和xpath。
1)cssSelector
选择器的功能:选中页面中指定的标签元素。选择器的种类分为基础选择器和复合选择器,常见的元素定位方式可以通过id选择器和子类选择器来进行定位。
定位百度首页的“百度热搜”元素,可以使用通过id选择器和子类选择器进行定位:#s-hotsearch-wrapper > div
2)xpath
XML路径语言,不仅可以在XML文件中查找信息,还可以在HTML中选取节点。xpath使用路径表达式来选择xml文档中的节点。xpath语法中:
①.获取HTML页面所有的节点://*
②.获取HTML页面指定的节点://[指定节点] eg://ul:获取HTML页面所有的ul节点
③.获取一个节点中的直接子节点:/ eg://span/input:获取span标签下的子节点input
④.获取一个节点的父节点:.. eg://input/..:获取input节点的父节点
⑤.实现节点属性的匹配:[@...] eg://*[@id='kw']:匹配HTML页面中id属性为kw的节点
⑥.使用指定索引的方式获取对应的节点内容:
eg:百度首页通过://div/ul/li[3]:定位到第三个百度热搜标签
注意:xpath的索引是从1开始的。
笔记:虽然我们可以通过鼠标右键直接复制对应元素的表达式,但是并非手动复制的selector/xpath表达式并不⼀定满足我们的需要,有时候是需要我们自己进行编写表达式的。
3)查找符合条件的元素
注意:对于复制的元素表达式可以做一次检查,在开发者工具的源代码页面中,使用快捷键Ctrl+F(快速查找),将复制的表达式进行搜索,确认一下是否是复制正确的,且为唯一。
获取元素的方法:
findElement(); 查找一个符合条件的元素
findElements(); 查找所有符合条件的元素
关键示例:
//对象.findElement(By.[根据什么查找]).行为; driver.findElement(By.xpath("//*[@id=\"chat-textarea\"]")).sendKeys("淘宝");2.操作测试对象
介绍:获取到了页面的元素之后,接下来就是要对元素进行操作了。常见的操作有点击、提交、输入、清除、获取文本。
1)点击/提交对象
click()
//找到百度⼀下按钮并点击 driver.findElement(By.cssSelector("#su")).click();2)模拟按键输入
sendKeys("")
driver.findElement(By.cssSelector("#kw")).sendKeys("输⼊⽂字");3)清除文本内容
输入文本后又想换一个新的关键词,清空输入框:
clear()
driver.findElement(By.cssSelector("#kw")).sendKeys("hello"); driver.findElement(By.cssSelector("#kw")).clear(); driver.findElement(By.cssSelector("#kw")).sendKeys("world!");4)获取文本信息
获取到对应的元素文本校验打印,获取文本信息:
getText()
String bdtext = driver.findElement(By.xpath("//*[@id="title-content"]/span[1]")).getText(); System.out.println("打印的内容是:"+bdtext);注意:文本和属性值是不同的,例如:输入框里的内容是文本,而我们所看到的百度按钮,上面的文字“百度一下”是按钮的属性值,获取属性值需要使用方法 getAttribute("属性名称") ;
5)获取当前页面标题
getTitle()
6)获取当前页面URL
getCurrentUrl()
3.窗口
介绍:当我们手工测试的时候,页面上有多个窗口时,可以通过观察来判断当前要操作的窗口是哪一个。但是对于程序来说,它是无法自主切换窗口的,如果不去修改指定,它只会操作默认的窗口。
想要让程序能够切换到别的窗口,需要用到属性句柄(handle),浏览器的每一个窗口都有唯一的属性句柄,知道属性句柄之后,就可以通过句柄来使程序切换窗口。
获取当前页面句柄:
getWindowHandle();
获取所有页面句柄:
getWindowHandles();
1)切换窗口
切换当前窗口为最新页面:
String curWindow = driver.getWindowHandle(); Set<String> allWindow = driver.getWindowHandles(); for( String w : allWindow){ if(w!=curWindow){ driver.switchTo().window(w); } }注意:执行了driver.close()之前需要切换到未被关闭的窗口。
2)设置窗口大小
//窗⼝最⼤化 driver.manage().window().maximize(); //窗⼝最⼩化 driver.manage().window().minimize(); //全屏窗⼝ driver.manage().window().fullscreen(); //⼿动设置窗⼝⼤⼩ driver.manage().window().setSize(new Dimension(1024, 768));3)屏幕截图(重要)
自动化脚本编写完成后,当我们运行自动化脚本在机器上自主运行,如果出现了报错,我们是不知道的。
但是可以通过别的方式来获取错误信息和内容,比如:添加日志,记录错误信息。通过截图,记录遇见的错误场景。
屏幕截图方法需要额外导入新的依赖:
<dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.6</version> </dependency>方法:
File file = ((TakesScreenshot)webDriver).getScreenshotAs(OutputType.FILE); FileUtils.copyFile(file,new File(filename));代码示例:
demo1:
//简单案例 File srcfile = driver.getScreenshotAs(OutputType.FILE); FileUtils.copyFile(srcfile,new File("my.png")); //完整案例 List<String> times = getTime(); //⽣成的⽂件夹路径./src/test/autotest-年-月-日/方法名-时分秒.png String filename ="./src/test/autotest-"+times.get(0)+"/"+str+"- "+times.get(1)+".png"; File srcfile = driver.getScreenshotAs(OutputType.FILE); //把屏幕截图放到指定的路径下 FileUtils.copyFile(srcfile,new File(filename));demo2:
public static void TakeScreenShotTo(WebDriver driver) throws IOException { //创建File文件并调用截图方法 File srcfile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE); //⽣成的⽂件夹路径./src/test/autotest-年-月-日/调用的方法名-时分秒毫秒.png(备注:生成量大时,以秒为单位可能重复,所以用毫秒) //创建时间格式化对象 simdir=>文件目录的时间格式 simfile=>文件名的时间格式 SimpleDateFormat simdir = new SimpleDateFormat("yyyy-MM-dd"); SimpleDateFormat simfile = new SimpleDateFormat("HHmmssSSS"); //创建字符串对象获取生成的结果 dirtime=>文件目录的时间 filetime=>文件名的时间 String dirtime = simdir.format(System.currentTimeMillis()); String filetime = simfile.format(System.currentTimeMillis()); //获取当前方法的名称 StackTraceElement[] stackTraceElements = new Throwable().getStackTrace(); StackTraceElement element = stackTraceElements[0]; String methodName = element.getMethodName(); //文件目标路径 // 示例模板=>./src/test/autotest-2026-09-04/TakeScreenShot-1219315.png String fileName = "./src/test/autotest-" + dirtime + "/" + methodName + "-" + filetime + ".png"; //将文件保存到指定位置 FileUtils.copyFile(srcfile, new File(fileName)); }4.等待
1)强制等待
Thread.sleep()
优点:使用简单,调用的时候简单有效(适合自己测试的时候使用)
缺点:影响运行效率,浪费大量时间(真正自动化测试时,如果每次都强制等待,将会使效率大大降低)
2)隐式等待
介绍:隐式等待是一种智能等待,他可以规定在查找元素时,在指定时间内不断查找元素。如果找到则代码继续执行,直到超时没找到元素才会报错。
implicitlyWait() 参数:Duration类中提供的毫秒、秒、分钟等方法。
//隐式等待1000毫秒 driver.manage().timeouts().implicitlyWait(Duration.ofMillis(1000)); //隐式等待5秒 driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5));隐式等待作用域是整个脚本的所有元素。即只要driver对象没有被释放掉(driver.quit()),隐式等待就一直生效。
优点:智能等待,作用于全局
缺点:隐式等待仅可以对页面内的元素生效,而对于页面内容之外的则无效,如网页的名称,地址栏,弹窗等。
笔记:隐式等待 是 WebDriver 全局的设置,一旦设置,作用于整个driver生命周期,对所有findElement和findElements调用都生效。
3)显示等待
介绍:显式等待也是一种智能等待,在指定超时时间范围内只要满足操作的条件就会继续执行后续代码。
new WebDriverWait(driver, Duration.ofSeconds(3)).until($express)
$press:涉及到selenium.support.ui.ExpectedConditions包下的ExpectedConditions类
返回值:boolea
//创建显示等待对象并绑定,等待3秒 WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(3)) //等待,直到#id元素可以点击为止 wait.until(ExpectedConditions.elementToBeClickable(By.cssSelector("#id")));ExpectedConditions预定义方法的一些示例:
- elementToBeClickable(By locator)——用于检查元素的期望是可见的并已启用,以便您可以单击它。
- textToBe(By locator, String str)——检查元素。
- presenceOfElementLocated(By locator)——检查页面的DOM上是否存在元素。
- urlToBe(java.lang.String url)——检查当前页面的URL是一个特定的URL。
- visibilityOfElementLocated(By)——元素可见(要输入内容或读取文本前)
- alertIsPresent()——弹窗出现(处理
alert/confirm) - invisibilityOfElementLocated(By)——元素消失(等待 loading 动画结束)
优点:显式等待是智能等待,可以自定义显式等待的条件,操作灵活
缺点:写法复杂
隐式等待Vs显示等待:
| 对比项 | 隐式等待(Implicit Wait) | 显式等待(Explicit Wait) |
|---|---|---|
| 作用范围 | 全局,作用于所有 findElement | 局部,只作用于指定的元素 |
| 等待条件 | 固定:元素存在(DOM 中出现) | 自定义:可见、可点、可选、有值等 |
| 生效时间 | 整个 driver 生命周期 | 每次单独设置 |
| 代码写法 | 一行搞定 | 需要创建 WebDriverWait 对象 |
| 推荐度 | 每次都加上 | 复杂的测试交互,需要加上 |
注意:推荐将显示等待和隐式等待搭配使用,将隐式等待作用在元素上,显示等待作用在非元素上。显示等待和隐式等待可以混用(但不推荐),两者相结合所产生的时间不可预测,比如当两者都用作页面元素上(注:该元素并不存在,做测试),隐式等待10s,显示等待5s,结果为10s左右(会浮动,并不精确)。
5.浏览器导航
1)打开网站
// 更⻓的⽅法 driver.navigate().to("https://selenium.dev"); // 简洁的⽅法 (推荐,最常用) driver.get("https://selenium.dev");2)浏览器的后退、前进、刷新
//后退 driver.navigate().back(); //前进 driver.navigate().forward(); //刷新 driver.navigate().refresh();6.弹窗
介绍:在网页中是找不到任何元素的,需要使用selenium提供的Alert接口来触发弹窗。弹窗分为三种警告弹窗、确认弹窗、提示弹窗。
Alert弹窗里包含四种操作:
①.void dismiss(); //取消
②.void accept(); //确认
③.String getText(); //获取内容
④.void sendKeys(String keysToSend); //输入值
1)警告弹窗
//创建一个警告弹窗 JavascriptExecutor js = (JavascriptExecutor) driver; js.executeScript("alert('这是一个警告弹窗!')"); //将页面的控制切换到弹窗上,获取弹窗的控制 Alert alert = driver.switchTo().alert(); alert.accept(); //确认备注:警告弹窗比较特别,它只有一个选项,所以accept和dismiss都可以使用,功能都是关闭弹窗。
2)确认弹窗
//创建一个确认弹窗 JavascriptExecutor js = (JavascriptExecutor) driver; js.executeScript("confirm('这是一个确认弹窗,要删除吗?')"); //将页面的控制切换到弹窗上,获取弹窗的控制 Alert alert = driver.switchTo().alert(); alert.accept(); //确认 alert.dismiss(); //取消3)提示弹窗
//创建一个提示弹窗 JavascriptExecutor js = (JavascriptExecutor) driver; js.executeScript("prompt('这是一个提示弹窗,请输入你的名字:')"); //将页面的控制切换到弹窗上,获取弹窗的控制 Alert alert = driver.switchTo().alert(); alert.sendKeys("张三"); //输入值 alert.accept(); //确认 alert.dismiss(); //取消注意:如果出现弹窗,必须对弹窗进行处理,关闭弹窗之后才能对页面其他元素进行操作。
7.文件上传
点击文件上传的场景下会弹窗系统窗口,进行文件的选择。
selenium无法识别非web的控件,上传文件窗口为系统自带,无法识别窗口元素但是可以使用sendkeys来上传指定路径的文件,达到的效果是一样的。
WebElement ele = driver.findElement(By.cssSelector("body > div > div > input[type=file]")); ele.sendKeys("D:\\selenium2html\\selenium2html\\upload.html");8.浏览器参数设置
1)设置无头模式
介绍:无头模式就是不展示测试过程(默认为有头模式)。正常在自动化测试的过程中,测试人员不会一直盯着自动化执行的效果,而是让自动化脚本自动执行,通过执行出的结果去分析。
options.addArguments("--headless");2)设置浏览器加载策略
介绍:当访问资源量过大的网站时,资源并不能很快的加载处理(比如:b站、抖音等网站,涵盖大量资源,不能一下子加载完所有资源的),我们也并不能总是去等待它所有的资源加载完再执行测试,所以我们可以通过设置浏览器加载策略来解决这个问题。
浏览器加载设置:options.setPageLoadStrategy(PageLoadStrategy.选项);
options.setPageLoadStrategy(PageLoadStrategy.EAGER);其中PageLoadStrategy有三个选择值:
①.NONE("none"); //完全不阻塞WebDriver,进入直接开始测试
②.EAGER("eager"); //DOM访问准备就绪(页面元素格式等基本内容加载完成),但是存在其他资源还在加载,比如图片,视频等
③.NORMAL("normal"); //默认值,等待所有资源都加载完成
9.Actions接口
介绍:网页的元素有时候是多层嵌套的,我们无法轻易获取它的焦点,就可以通过seleunim来模拟人的键鼠操作。
详情见seleunim参考手册:Selenium 浏览器自动化项目 | Selenium
键鼠操作:
10.开启断言
介绍:对于网页文本信息的校验我们就可以通过断言来实现。
在Java中启用断言:
1.打开运行配置:在 IDEA 右上角,点击当前运行类旁边的下拉菜单,选择Edit Configurations...
2.添加 VM 参数:在对应的运行配置中,找到VM options输入框,填入
-ea -Dfile.encoding=UTF-8(开启断言 + UTF-8编码)
四、总结
面试考点:
NoSuchElementException:找不到元素
可能的原因:
1)页面元素表达式复制错误 eg:#kw错打成了kw
2)复制的表达式与代码中By的搜索方式不匹配 eg:复制Xpath://*[@id="chat-submit-button"]却用的By.clsSelector
3)自动化所加载的页面与手工打开的不一致 eg:手动打开的页面是登录了账号的,自动的没有登录
4)搜索的是动态元素,其表达式是会变化的
5)代码执行的速度比页面加载的速度更快
常见报错速查表:
| 报错信息 | 一句话原因 | 最快解决方案 |
|---|---|---|
| NoSuchElementException | 定位器写错 / 元素没加载 / 在 iframe 里 | ① Console 验证 Xpath ② 加显式等待 ③ 检查 iframe |
| ElementNotInteractableException | 元素找到了,但点不了(被挡/不可见/未启用) | WebDriverWait + elementToBeClickable + 滚动 |
| TimeoutException | 等待超时(元素没在规定时间内出现) | 增加超时时间 / 换更合适的等待条件 |
| StaleElementReferenceException | 元素引用过期(页面刷新/跳转后老元素失效) | 不要缓存元素,每次操作前重新 findElement |
| NoAlertPresentException | 调了 switchTo().alert() 但页面上没弹窗 | 先用 isAlertPresent() 判断,或用 alertIsPresent() 等待 |
| InvalidArgumentException | 方法参数传错了(URL 缺协议 / Xpath 引号不匹配) | 检查参数格式,URL 加 http://,Xpath 用英文引号 |
| JavascriptException | 注入的 JS 代码语法错误或被浏览器拦截 | Console 预验证 JS,检查引号是否为英文 |
| SessionNotCreatedException | ChromeDriver 版本与浏览器不匹配 | 更新 WebDriverManager 或手动下载匹配驱动 |
| NoSuchWindowException | 切换窗口时句柄失效(窗口已关或未打开) | 先 getWindowHandles() 获取所有句柄再切换 |
| InvalidSelectorException | Xpath 或 CSS 语法错误(如 //*[@id='kw' 缺括号) | 检查定位器括号是否成对,引号是否闭合 |