文章目录
谷歌浏览器升级到111版本之后,Java版本的selenium和Chrome不兼容
所以更换浏览器和驱动,使用edge浏览器和edge驱动,因为本篇是在 chrome 浏览器 111 版本之前写的,所以
在看到创建 ChromeDriver driver = new ChromeDriver(); 驱动对象的操作,请将这段代码替换为
EdgeOptions options = new EdgeOptions(); options.addArguments("-remote-allow-origins=*"); EdgeDriver driver = new EdgeDriver(options)
EdgeOptions
是用于设置 Edge 浏览器的选项的类;options.addArguments("-remote-allow-origins=*")
是设置 Edge 浏览器允许跨域请求的选项,即允许 WebDriver 与浏览器在不同的域之间通信。- 如果不使用 EdgeOptions 对象来设置,就无法实现这个功能。而 ChromeDriver 则没有类似的选项需要设置,所以可以直接使用 ChromeDriver driver = new ChromeDriver() 来创建驱动对象但因为版本不兼容就不用 chrome 了。
1. 什么是自动化
作用:通过自动化测试有效减少人力的投入,同时提高了测试的质量和效率
概念:自动化测试指软件测试的自动化,在预设状态下运行应用程序或者系统,预设条件包括正常和异常,最后评估运行结果。将人为驱动的测试行为转化为机器执行的过程
比如,回归测试版本越来越多,版本回归的压力越来越大,仅通过人工测试来回归所有的版本肯定是不现实的,所以我们需要借助自动化测试
2. 自动化测试的分类
- 接口自动化测试
- UI自动化测试(界面测试)
- 移动端自动化测试
- web 端自动化测试
3. selenium(web 自动化测试工具)
(1)选择 selenium 作为的 web 自动化测试工具是因为
- 开源免费
- 支持多浏览器,比如 Chrome、Firefox、IE浏览器…
- 支持多系统,比如 Linux、Windows、MacOs
- 支持多语言,比如 Java、Python、JavaScript…
- selenium 包提供了很多可供测试使用的 API
(2)环境部署
如果想要使用 selenium 实施 Web 自动化测试,需要的环境是什么
Chrome 浏览器、谷歌驱动(ChromeDriver)、selenium 工具包
(3)什么是驱动?
人工测试的情况下,人来手动的打开浏览器,那么驱动就是人力
对自动化来说,代码不能够直接打开浏览器,需要借助驱动程序才能打开浏览器
selenium 编写的自动化脚本是如何打开浏览器(selenium Driver 浏览器三者之间的关系)
驱动要接受 selenium 脚本发送过来的 http 请求并解析
(4)selenium 原理主要包含这几个方面:
- WebDriver:WebDriver 是 Selenium 的核心组件,它负责和浏览器进行交互,用来模拟用户的操作。WebDriver 可以通过不同的浏览器驱动来实现对不同浏览器的支持。
- 浏览器驱动:浏览器驱动是 Selenium 与浏览器进行交互的桥梁,它负责把 Selenium 的命令转换为浏览器可以理解的指令。Selenium 支持多种浏览器驱动,比如 chromeDriver、EdgeDriver等
- 客户端库:客户端库时 Selenium 的 API,它提供一组方法和属性,用于控制 WebDriver 和 浏览器驱动。客户daunt可以使用多种编程语言来实现,比如 java python 等
总体流程的话就是,自动化测试代码发送请求到浏览器驱动,然后浏览器驱动来解析自动化代码,解析为浏览器可以读懂的指令操作,最终浏览器来执行执行,模拟用户的操作。
4. 一个简单的自动化例子
创建 Maven 项目,导入 selenium 包
<dependencies><dependency><groupId>org.seleniumhq.selenium</groupId><artifactId>selenium-java</artifactId><version>4.0.0</version></dependency></dependencies>
简单自动化示例主要包含五个步骤
- 创建驱动实例,创建会话(实例化 ChromeDriver 对象)
- 访问网站(对象.get(“网站”))
- 查找元素(对象.findElement(By.cssSelector(“#网址元素id”)).sendKeys(“输入内容”))
- 操作元素(对象.findElement(By.cssSelector(“#网址元素id”)).click())
- 结束会话(对象.quit())
packagecom.autotest0113;importorg.openqa.selenium.By;importorg.openqa.selenium.WebElement;importorg.openqa.selenium.chrome.ChromeDriver;importjava.util.List;publicclassFirstAutotest{// 在百度网址搜索关键词 “胡歌”publicvoidhuge()throwsInterruptedException{// 1.打开浏览器ChromeDriver chromeDriver =newChromeDriver();Thread.sleep(3000);// 2.在浏览器里输入百度网址,访问百度首页
chromeDriver.get("https://www.baidu.com");Thread.sleep(3000);// 3.找到百度首页输入框元素,并输入关键词 “胡歌”
chromeDriver.findElement(By.cssSelector("#kw")).sendKeys("胡歌");Thread.sleep(3000);// 4.找到百度首页 “百度一下” 按钮,并点击一下
chromeDriver.findElement(By.cssSelector("#su")).click();Thread.sleep(3000);// 5.结束会话(关闭浏览器)
chromeDriver.quit();}}
packagecom.autotest0113;importsun.text.normalizer.CharTrie;publicclassRunAutoTest{publicstaticvoidmain(String[] args)throwsInterruptedException{FirstAutotest firstAutotest =newFirstAutotest();
firstAutotest.huge();}}
5. selenium 常用方法
5.1 查找页面元素 findElement ()
参数:By 类(提供通过什么方式来查找元素)
返回值:webElemen
当元素可以在页面找到的情况下,程序正常退出
当元素在页面找不到的情况下,程序执行报错
findElements()方法
参数:By 类(提供通过什么方式来查找元素)
返回值:List
publicvoidmethodTest(){ChromeDriver driver =newChromeDriver();
driver.get("https://www.baidu.com");
driver.findElement(By.cssSelector("#kw"));List<WebElement> elements= driver.findElements(By.className("hotsearch-item"));for(WebElement element : elements){System.out.println(element.getText());}
driver.findElement(By.cssSelector("#su"));
driver.quit();}
5.2 元素的定位 By 类
5.3 xpath 路径语言
语法:
层级:/子级 // 跳级
属性:@
函数:contains()…
自动化里要求元素的定位必须要唯一,但是手动在页面复制 selector 或者 path 元素不一定是唯一的,需要我们进行手动修改到唯一
6. 常见的元素操作
6.1 输入文本 sendKeys
sendKeys,仅适用于文本字段和内容可编辑的元素
// 找到百度搜索框WebElement ele = driver.findElement(By.cssSelector("#kw"));// 在输入框输入文本
ele.sendKeys("qq音乐");// 找到百度搜索框并输入文本// driver.findElement(By.cssSelector("#kw")).sendKeys("qq音乐");
6.2 点击 click
// 3.找到百度搜索框并输入文本
driver.findElement(By.cssSelector("#kw")).sendKeys("qq音乐");
6.3 提交 submit (通过回车键提交)
submit 仅适用于表单元素,selenium 官方不推荐使用 submit,更推荐 click
// 找到百度搜索框并输入文本
driver.findElement(By.cssSelector("#kw")).sendKeys("qq音乐");// 找到百度一下通过回车键进行提交
driver.findElement(By.cssSelector("#su")).submit();
6.4 请求 clear
clear:适用于频繁测试输入是否可以重复输入
// 清除输入框的内容
driver.findElement(By.cssSelector("#kw")).clear();
6.5 获取文本 getText
// 获取文本String text = driver.findElement(By.cssSelector("#s-top-left > div > a")).getText();System.out.println("获取到的文本:"+ text);
6.6 获取属性对应的值 getAttribute
// 获取属性的值String buttonText = driver.findElement(By.cssSelector("#su")).getAttribute("type");System.out.println("获取到的属性名:"+ buttonText);String buttonText1 = driver.findElement(By.cssSelector("#su")).getAttribute("id");System.out.println("获取到的属性名:"+ buttonText1);String buttonText2 = driver.findElement(By.cssSelector("#su")).getAttribute("value");System.out.println("获取到的属性名:"+ buttonText2);
6.7 获取页面的标题和 URL
System.out.println(driver.getTitle());System.out.println(driver.getCurrentUrl());
driver.findElement(By.cssSelector("#kw")).sendKeys("你好");
driver.findElement(By.cssSelector("#su")).click();System.out.println(driver.getTitle());System.out.println(driver.getCurrentUrl());
7. 窗口
7.1 窗口大小的设置(manage().window())
最大化、最小化、全屏窗口、手动设置窗口大小
publicvoidwindowConTrol()throwsInterruptedException{Thread.sleep(3000);// 窗口最大化
driver.manage().window().maximize();Thread.sleep(3000);// 窗口最小化
driver.manage().window().minimize();Thread.sleep(3000);// 全屏
driver.manage().window().fullscreen();Thread.sleep(3000);// 手动设置窗口大小
driver.manage().window().setSize(newDimension(1024,768));Thread.sleep(2000);
driver.quit();}
7.2 窗口的切换
打开百度首页,点击图片超链接进入到百度图片首页,获取百度图片页面的 “百度一下” 按钮
publicvoidwindowConTrol()throwsInterruptedException,IOException{// 窗口切换
driver.get("https://www.baidu.com");
driver.findElement(By.cssSelector("#s-top-left > a:nth-child(6)")).click();Thread.sleep(3000);
driver.findElement(By.cssSelector("#homeSearchForm > span.s_btn_wr > input"));
driver.quit();}
结果报错了,找不到页面元素
这是是因为,当浏览器每次打开一个标签页的时候,会自动的给每个标签页进行标识,这个叫做句柄
可以通过 getWindowHandles() 获取所有标签页的句柄 Set,然后再通过getWindowHandle() 获取当前页面的句柄,然后遍历所有标签页的句柄,如果当前页的句柄和遍历 Set 中的句柄不同,就通过 switchTo().window() 方法进行窗口切换
publicvoidwindowConTrol()throwsInterruptedException,IOException{
driver.get("https://www.baidu.com");
driver.findElement(By.cssSelector("#s-top-left > a:nth-child(6)")).click();Thread.sleep(3000);// 获取当前页面的句柄String curHandle = driver.getWindowHandle();System.out.println("当前页面的句柄:"+ curHandle);// 获取所有标签的句柄Set<String> handles = driver.getWindowHandles();for(String handle : handles){if(handle != curHandle){
driver.switchTo().window(handle);}}
driver.findElement(By.cssSelector("#homeSearchForm > span.s_btn_wr > input"));Thread.sleep(3000);
driver.quit();}
那么当我们打开了好几个窗口,怎么切换?
自动化基本没有这样的场景,所以这里不用考虑太多
8. 屏幕截图 getScreenshotAs
这里需要在 pom.xml 中引入屏幕截图文件需要用到的包
<!-- 保存屏幕截图文件需要用到的包--><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.6</version></dependency>
需要注意的一点是,当代码执行到查找结果页面元素的时候,页面还没有加载完全,此时程序执行的速度是比,页面渲染的速度更快的,所以要注意在代码中添加等待机制,让页面先渲染一下,再截图
publicvoidwindowConTrol()throwsInterruptedException,IOException{// 屏幕截图
driver.get("https://www.baidu.com");
driver.findElement(By.cssSelector("#kw")).sendKeys("网易云音乐");
driver.findElement(By.cssSelector("#su")).click();Thread.sleep(3000);// 屏幕截图(保存现场)File srcfile = driver.getScreenshotAs(OutputType.FILE);// 把屏幕截图好的文件放到指定的路径下String filename ="my.png";FileUtils.copyFile(srcfile,newFile(filename));
driver.findElement(By.cssSelector("#content_left"));
driver.quit();}
我这里的代码文件名为固定格式,如果程序多次执行生成的图片文件会被同名覆盖,这就可以将文件名的命名添加动态数据(时间戳)
9. 等待
程序执行的速度要比浏览器渲染的速度要快很多
四种等待:强制等待、隐式等待、显示等待、流畅等待
需要注意:显示等待、隐式等待,不能同时使用,同时使用可能会出现意想不到的等待结果
9.1 强制等待
在 8. 屏幕截图时,为了让页面渲染完全后才进 行屏幕截图,中间进行了等待 3s (Thread.sleep())
这个就会使 程序阻塞进行,这种方式在自动化测试中会用到,但用的不是特别多,这是因为
每一个自动化方法就是一个自动化测试用例,比如一个用例需要 10s,100测试用例 1000s,200个用例 2000s,这样耗费时间太多了,只能接受十几秒或几分钟内
9.2 隐式等待
隐式等待会作用于 driver 的整个生命周期
隐式等待会一直轮询判断元素是否存在,如果不存在就等待设置好的时间里不断的进行轮询,直到元素能够被找到
publicclass autoTest {ChromeDriver driver =newChromeDriver();publicvoidwaitContro(){// 添加隐式等待
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(3));
driver.get("https://www.baidu.com");
driver.findElement(By.cssSelector("#kw")).sendKeys("迪丽热巴");
driver.findElement(By.cssSelector("#su")).click();
driver.findElement(By.cssSelector("#content_left"));
driver.quit();}}
9.3 显示等待
publicclass autoTest {ChromeDriver driver =newChromeDriver();publicvoidwebDriverWait(){
driver.get("https://www.baidu.com");
driver.findElement(By.cssSelector("#kw")).sendKeys("迪丽热巴");
driver.findElement(By.cssSelector("#su")).click();// 添加显示等待newWebDriverWait(driver,Duration.ofSeconds(5)).until(driver->driver.findElement(By.cssSelector("#content_left")));
driver.quit();}}
10. 浏览器导航 navigate
浏览器的前进(forward)、后退(back)、刷新(refresh)
publicclass autoTest {ChromeDriver driver =newChromeDriver();// 浏览器导航publicvoidnavigateConTrol(){
driver.get("https://www.baidu.com");// driver.navigate().to("https://www.baidu.com");// 想要回退到访问百度网址之前的状态
driver.navigate().back();// 前进 进入到百度首页
driver.navigate().forward();// 刷新百度首页
driver.navigate().refresh();
driver.quit();}}
11. 弹窗
弹窗的类型:警告弹窗、确认弹窗、提示弹窗
处理弹窗的步骤:
- 将 driver 对象作用到弹窗上(切换到弹窗) driver.switchTo.alert()
- 选择确认 accept() / 取消 dismiss() (提示弹窗 输入文本 sendkeys 在页面上是看不到输入文本的执行效果的)
虽然警告弹窗只有确认按钮,但 accept 和 dismiss 都能处理
虽然警告弹窗和确认弹窗都没有输入文本的地方,但如果要执行 alert.sendKeys 代码,也是不会报错的
ChromeDriver chromeDriver =newChromeDriver();// 提示弹窗voidAlertcontro()throwsInterruptedException{
chromeDriver.get("file:///D:/%E6%8F%90%E7%A4%BA%E5%BC%B9%E7%AA%97.html");Thread.sleep(3000);// 打开弹窗
chromeDriver.findElement(By.cssSelector("body > input[type=button]")).click();Thread.sleep(3000);// 切换到弹窗进行弹窗处理Alert alert = chromeDriver.switchTo().alert();Thread.sleep(3000);// 1. 输入
alert.sendKeys("666");Thread.sleep(3000);// 2. 点击确认
alert.accept();Thread.sleep(3000);// 取消
alert.dismiss();
chromeDriver.quit();}
12. 选择框 select
选项的选择方式:根据文本选择(selectByVisibleText)、根据属性值选择(selectByValue)、根据序号选择(selectByIndex)
ChromeDriver chromeDriver =newChromeDriver();voidselectControll()throwsInterruptedException{
chromeDriver.get("file:///D:/%E9%80%89%E6%8B%A9%E6%A1%86.html");WebElement ele = chromeDriver.findElement(By.cssSelector("#ShippingMethod"));Thread.sleep(2000);// 先创建选择框对象Select select =newSelect(ele);Thread.sleep(2000);// 根据文本来选择// select.selectByVisibleText("333");// 根据属性值选择// select.selectByValue("222");// 根据序号选择【序号从 0 开始】
select.selectByIndex(3);Thread.sleep(2000);
chromeDriver.quit();}
13. 执行脚本 executeScript
executeScript(参数:JS)
ChromeDriver chromeDriver =newChromeDriver();voidscriptControll()throwsInterruptedException{
chromeDriver.get("https://image.baidu.com/");Thread.sleep(3000);// 执行 JS 命令:让页面置顶/置底
chromeDriver.executeScript("document.documentElement.scrollTop=500");Thread.sleep(3000);
chromeDriver.executeScript("document.documentElement.scrollTop=0");Thread.sleep(3000);
chromeDriver.quit();}// 也可以通过 JS 代码来操作在输入框中搜索voidscriptControll()throwsInterruptedException{
chromeDriver.get("https://www.baidu.com");// 找到百度搜索框,输入 “迪丽热巴”
chromeDriver.executeScript("var ss = document.querySelector(\"#kw\");ss.value = '迪丽热巴';");Thread.sleep(3000);
chromeDriver.quit();}
14. 文件上传
ChromeDriver driver =newChromeDriver();// 文件上传voidfileUploadControll()throwsInterruptedException{
driver.get("file:///D:/%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0.html");
driver.findElement(By.cssSelector("#avatar")).sendKeys("D:\\微信图片_20230212212832.jpg");Thread.sleep(3000);
driver.quit();}
15. 浏览器的参数设置 ChromeOptions
无头模式:在实际工作中,测试人员将自动化部署在机器上自动的执行,测试人员看不到测试过程,而是直接查看自动化执行的结果
有头模式:就是程序在自动的测试,我们是可以看到执行测试的过程界面
浏览器的参数设置需要在创建浏览器对象之前
voidparamsControll(){// 先创建选项对象,然后再设置浏览器参数ChromeOptions options =newChromeOptions();
options.addArguments("-headless");// 百度搜索迪丽热巴ChromeDriver driver =newChromeDriver(options);
driver.get("https://www.baidu.com");
driver.findElement(By.cssSelector("#kw")).sendKeys("迪丽热巴");
driver.findElement(By.cssSelector("#su")).click();
driver.quit();}
16. 单元测试工具 Junit
自动化就是 selenium 脚本来实现的,junit 是 java 的单元测试工具,只不过在实现自动化的时候需要借用一下 junit 库里面提供的一些注解(junit5)
<dependency><groupId>org.junit.platform</groupId><artifactId>junit-platform-suite</artifactId><version>1.8.2</version><scope>test</scope></dependency>
@Test(测试方法)、@BeforeEach(每个测试用例前执行一次)、@BeforeAll(所有测试用例前执行一次)、 @AfterEach(每个测试用例之后执行一次)、@AfterAll(所有测试用例之后执行一次)
并且 BeforeAll 和 AfterAll 注解的方法必须为静态方法
(1)注解
junit 中提供了注解功能
@Test 表示方法是测试方法,执行当前这个类时,会自动的执行该类下所有带 @Test 注解的用例
publicclass junitTest {@Testvoidbbb(){System.out.println("bbbb");}@Testvoidccc(){System.out.println("cccc");}}
@BeforeEach 表示当前的方法需要在每个用例执行之前都执行一次
publicclass junitTest {@BeforeEachvoidaaa(){System.out.println("aaaa");}@Testvoidbbb(){System.out.println("bbbb");}@Testvoidccc(){System.out.println("cccc");}}
@BeforeAll 当前的方法需要在当前类下所有用例之前执行一下,被该注解修饰的方法必须为静态方法
publicclass junitTest {@BeforeAllstaticvoidaaa(){System.out.println("aaaa");}@Testvoidbbb(){System.out.println("bbbb");}@Testvoidccc(){System.out.println("cccc");}}
@AfterEach 在每个用例执行之后都要执行一次
publicclass junitTest {@AfterEachvoidaaa(){System.out.println("aaaa");}@Testvoidbbb(){System.out.println("bbbb");}@Testvoidccc(){System.out.println("cccc");}}
@AfterAll
publicclass junitTest {@AfterAllstaticvoidaaa(){System.out.println("aaaa");}@Testvoidbbb(){System.out.println("bbbb");}@Testvoidccc(){System.out.println("cccc");}}
16.1 Junit 的执行顺序
注意看两次代码的执行顺序
可以看到测试用例的执行并不会按照我们编写测试用例的顺序来执行,那么这就会出现一些问题
比如说对博客的登录系统编写测试用例,用例包含:
- 检查登录页面展现是否正确
- 检查正常登录 (跳转到博客首页 / 列表页)
- 异常登录
执行顺序的问题,就会导致比如说,先执行步骤二,那么此时是登录成功的,页面就会跳转,然后再执行步骤一就会 报错
1. 通过 order 注解来排序
- 先使用注解说明当前类下所有的用例需要使用 order 注解来进行排序,注解该注解必须要使用到类上
- 然后通过 Order 来指定用的执行具体顺序
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)publicclassJunitTest{@Test@Order(1)voidediloginTest(){System.out.println("loginTest");}@Test@Order(2)voidAindexTest(){System.out.println("indexTest");}@Test@Order(3)voideditTest(){System.out.println("editTest");}}
16.2 参数化
尽可能的通过一个用例,多组参数来模拟用户的行为
单参数:
@ParameterzedTest + @ValueSource(数据类型方法/加s = {参数1,参数2,参数3,…})
多参数:
@parameterizedTest + @CsvSource({“”, “”, '", …}) 每个双引号就是一组测试用例
@ParameterizedTest@CsvSource({"张三,22","李四,25","王五,35"})voidmuchParamsTest(String name,int age){System.out.println("name: "+ name +",age: "+ age);}
多参数(从第三方 csv 文件读取数据源)
@ParameterizedTest + @CsvFileSource(files = “文件路径+名字”)
这里的这个 csv 文件,不要直接改后缀生成,要用系统自带的 Excel 工具,来打开和编辑 csv 文件
@ParameterizedTest@CsvFileSource(files ="D:\\mycsv.csv")voidcsvfileParamsTest(String name,int age){System.out.println("name: "+ name +",age: "+ age);}
driver.navigate().back();
这个是模拟了浏览器的后退按钮,使得当前页面返回到上一个页面。这个方法可以用于测试中,例如在测试过程中需要回到之前的页面重新执行某些操作或者验证某些信息。
动态参数方法
// 通过动态方法来提供数据源@ParameterizedTest@MethodSource("methodParams")voiddynamicMethodParamsTest(String name,int age){System.out.println("name: "+ name +",age: "+ age);}staticStream<Arguments>methodParams()throwsInterruptedException{// 构造动态参数String[] arr =newString[5];for(int i =0; i < arr.length; i++){Thread.sleep(500);
arr[i]=System.currentTimeMillis()+"";}returnStream.of(Arguments.arguments(arr[0],20),Arguments.arguments(arr[1],20),Arguments.arguments(arr[2],20),Arguments.arguments(arr[3],20),Arguments.arguments(arr[4],20));}
16.3 测试套件
创建三个类,给每个类中都加上测试注解 @Test,如果要测试运行,只能一个类一个类运行,不能对三个类同时运行,
所以可以使用测试套件来同时运行多个测试类
创建一个类,通过 @Suite 注解标识该类为测试套件类(而不是测试类)
- 指定类来运行用例(要运行的用例必须要被 @Test 注解,除了参数化的用例)
/**
* @Description: 测试套件
* @Date 2023/3/7 21:29
*/@Suite@SelectClasses({aaa.class,bbb.class,ccc.class})publicclass runSuite {}
运行程序可以看到
- 指定包名来运行(第一种方法,如果类特别多的情况下,不太适合,可以指定包)
@Suite@SelectPackages("com.autoTest0303")publicclass runSuite {}
17. 断言 Assertions
断言匹配 assertEquals,断言不匹配 assertNotEquals
@Testvoidhuixiang(){ChromeDriver driver =newChromeDriver();
driver.get("https://www.baidu.com");String text = driver.findElement(By.cssSelector("#su")).getAttribute("value");//百度一下// 假如这里获取的属性不是百度一下,而是百度两下System.out.println(text);Assertions.assertEquals("百度两下",text);
driver.quit();}
断言结果为真 assertTrue,断言结果为假 assertFalse
@Testvoidddd(){Assertions.assertTrue(1==1);//正确}@Testvoideee(){Assertions.assertFalse(1==1);//报错}@Testvoidfff(){Assertions.assertFalse(1==0);//正确}
断言结构为空 assertNull,断言结果不为空 assertNotNull
@Testvoidggg(){String aaa =null;Assertions.assertNull(aaa);//通过}@Testvoidhhh(){Assertions.assertNotNull("你好");//通过}
版权归原作者 快到锅里来呀 所有, 如有侵权,请联系我们删除。