自动化测试
自动化概念
自动化就是代替人类行为完成操作
自动化在生活中处处可见

超时自动闸门,自动感应开门和关门
自动洗手液,可以直接通过感应出洗手液
在生活中自动化案例减少人力的消耗,同时提高生活质量
在自动化测试中也是如此,减少人力消耗提高测试效率和质量
目的 :主要是用于解决回归测试
回归测试 :
软件会有很多版本,会不断进行更新迭代,对其功能整体回归,为了避免新增功能影响到历史功能需要进行回归测试

问题:
1.自动化测试可以取代手动测试吗?
自动化测试不一定比手动测试更有保障系统可靠性,自动化测试程序也是由测试人员写的,后续修改功能/新增功能,需要对自动化程序进行维护和更新
2.自动化测试可以大幅度降低工作量?
不可以,只可以一定程度上降低工作量 ,可以提高测试的质量和效率
需求分析 - 测试计划 - 测试设计 - 执行测试 - 测试评估 - 上线
这里只有执行测试才会进行手工测试和自动化测试,其只是测试工作的一部分
自动化分类
接口自动化
接口自动化测试是一种用于测试应用程序接口(API)的自动化测试方法。其主要目的是验证接口是否按预期工作,并在不同输入和输出组合下是否具有正确的行为。通过编写自动化脚本,测试人员可以快速、准确地检测问题,从而提高测试效率和质量
UI自动化
UI(User Interface,即用户界面) 测试也成为界面测试,常见的UI自动化测试包含web自动化测试、移动端自动化测试 等等
客户端界面自动化测试分为:GUI自动化测试(PC)和移动端自动化测试(手机)
移动端测 通常不是将程序部署在移动端进行测试,而是需要安装模拟器,在电脑上编写自动化测试脚本对模拟器软件进行测试
并且难度较大,其稳定性没有接口自动化好
web自动化测试
通常是在浏览器上模拟操作,自动打开浏览器,访问其页面并进行一系列搜索和验证等行为
自动化测试金字塔

理想情况下是这样,在单元测试中投入少,回报率高可以有效的解决问题,但是实际上其是反过来的

Web自动化测试
驱动
web测试是需要先打开浏览器,通过访问web服务器对服务器界面进行一系列操作,手工测试,一般所有操作都需要手动完成,但是如果使用自动化程序如何打开浏览器呢?
像车有了驱动才可以跑起来
需要对应浏览器的驱动,每个浏览器的驱动(即WebDriver)不一样

驱动管理:
这里的驱动是可以手动下载 ,但是需要下载与浏览器匹配的驱动
像Chrome -> ChromeDriver,并且每个浏览器有很多版本,必须要下载与浏览器版本匹配的驱动

自动下载
Java提供了WebDriverManager自动化方式对Selenium WebDriver所需的驱动程序(如chromedriver、geckodriver、msedgedriver等)进⾏管理(即下载、设置和维护),其会根据所选浏览器及其对应版本下载
xml
<dependency>
<groupId>io.github.bonigarcia</groupId>
<artifactId>webdrivermanager</artifactId>
<version>5.8.0</version>
<scope>test</scope>
</dependency>
selenium是⼀个web⾃动化测试⼯具,里面放了丰富的方法
xml
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.0.0</version>
</dependency>
这里以Chrome谷歌浏览器驱动为例
手动下载谷歌驱动
https://googlechromelabs.github.io/chrome-for-testing/
绿色就是可以下载,选择和自己浏览器对应的版本

选择对应的系统版本,直接将URL复制进行搜索即可下载

例如:使用驱动打开百度浏览器 搜索时崎狂三 ,点击百度一下
使用手动下载的chrome驱动,需要和浏览器版本一致

java
public class runtest {
public static void main(String[] args) throws InterruptedException {
firstTest first = new firstTest();
first.search();
}
}
手动下载的驱动
java
//手动下载
public class firstTest {
//百度搜索关键词
void search() throws InterruptedException {
// 1、打开浏览器(驱动)
System.setProperty("webdriver.chrome.driver", "D:/chrome/chromedriver.exe");
// 2)添加浏览器配置
ChromeOptions options = new ChromeOptions();
//允许访问所有链接
options.addArguments("--remote-allow-origins=*");
WebDriver driver = new ChromeDriver(options);
// 2、输入网址
driver.get("https://www.baidu.com/");
Thread.sleep(1000);
// 3、找到输入框,输入 时崎狂三
driver.findElement(By.cssSelector("#chat-textarea")).sendKeys("时崎狂三");
Thread.sleep(1000);
// 4、找到百度一下按钮,并点击
driver.findElement(By.cssSelector("#chat-submit-button")).click();
// 5、关闭浏览器
Thread.sleep(3000);
driver.quit();
}
}
这里Thread是为了更好的观察其所有操作是否符合预期
java
//选定对应驱动位置
System.setProperty("webdriver.chrome.driver", "D:/chrome/chromedriver.exe");

自动下载驱动,但是可能会由于网络问题下载不成功
java
public class firstTest {
//百度搜索关键词
void search() throws InterruptedException {
// 1、打开浏览器(驱动)
// System.setProperty("webdriver.chrome.driver", "D:/chrome/chromedriver.exe");
WebDriverManager.chromedriver().setup();
// 2)添加浏览器配置
ChromeOptions options = new ChromeOptions();
//允许访问所有链接
options.addArguments("--remote-allow-origins=*");
WebDriver driver = new ChromeDriver(options);
// 2、输入网址
driver.get("https://www.baidu.com/");
Thread.sleep(1000);
// 3、找到输入框,输入 时崎狂三
driver.findElement(By.cssSelector("#chat-textarea")).sendKeys("时崎狂三");
Thread.sleep(1000);
// 4、找到百度一下按钮,并点击
driver.findElement(By.cssSelector("#chat-submit-button")).click();
// 5、关闭浏览器
Thread.sleep(3000);
driver.quit();
}
}
selenium+驱动+浏览器的工作原理

1.自动化脚本(Selenium)
测试人员编写的代码,遇到像click()等操作 这样的操作就会创建一个特定的Http请求 ,包含要执行的操作
2.WebDriver浏览器驱动
驱动内部的HTTP服务器会接收到来自脚本的HTTP请求 ,然后解析这个请求,驱动将通用的WebDriver命令 转换成对应浏览器能够理解的原生指令
3.浏览器
接收到驱动的指令以后就会进行执行
执行完之后,将结果返回给webDriver驱动,webDriver驱动将其打包成一个HTTP响应 ,将结果返回给自动化脚本
自动化测试常用函数
元素定位
查找元素
java
//返回多个
List<WebElement> findElements(By by);
//返回一个
WebElement findElement(By by);
使用selector选择器

java
public class runtest {
public static void main(String[] args) throws InterruptedException {
autotest test = new autotest();
test.search();
}
}
java
public class autotest {
public WebDriver driver = null;
//驱动
public void start(){
//打开浏览器驱动
WebDriverManager.chromedriver().setup();
//添加配置
ChromeOptions options = new ChromeOptions();
//运行访问所有连接
options.addArguments("--remote-allow-origins=*");
driver = new ChromeDriver(options);
}
//结束驱动
public void end(){
driver.quit();
}
//查找和定位元素
public void search() {
start();
driver.get("https://www.baidu.com/");
WebElement element = driver.findElement(By.cssSelector("#hotsearch-content-wrapper > li:nth-child(4) > a"));
System.out.println(element.getText());
end();
}
}

使用xpath可以获取到对应内容
这里查找多个元素是相同元素


打印百度热搜中的所有新闻

像这里查找多个元素都是同一路径下li
java
//查找和定位元素
public void search() {
start();
driver.get("https://www.baidu.com/");
List<WebElement> elements = driver.findElements(By.xpath("//*[@id=\"hotsearch-content-wrapper\"]"));
for(WebElement ele : elements){
System.out.println(ele.getText());
}
end();
}
发现这里打印结果不符合要求


因为上面未给出精确位置,这里需要指定是 li / a / span2
li下的a标签 ,a标签下的第二个span标签
java
//查找和定位元素
public void search() {
start();
driver.get("https://www.baidu.com/");
List<WebElement> elements = driver.findElements(By.xpath("//*[@id=\"hotsearch-content-wrapper\"]/li/a/span[2]"));
for(WebElement ele : elements){
System.out.println(ele.getText());
}
end();
}

这有很多定位方式

cssSelector
选择器功能:选中页面中指定的标签元素
分为基础选择器和复合选择器 常见的元素定位可以通过id选择器 或子类选择器选择

例如这里百度热搜按钮
#s-hotsearch-wrapper > div > a.hot-title > div
下一级:>
Xpath
XML路径语⾔,不仅可以在XML⽂件中查找信息,还可以在HTML中选取节点。
xpath使⽤路径表达式来选择xml⽂档中的节点
1.获取HTML页面中所有节点
//*

2.获取HTML页面指定节点
//指定节点
//ul:获取页面中所有ul节点

3.获取一个节点中的直接子节点
/
//ul/li
ul标签下的li标签

4.获取一格节点的父节点
/...

5.使用节点属性的匹配
@...
//*@id="hotsearch-content-wrapper"/li1/a/span2
像这里就是匹配HTML中id属性为hotsearch-content-wrapper下 /li1/a/span2标签

6.使用索引方式访问对应节点
这里索引下标是从1开始
像上面这里/li1/a/span2就是定位到span标签中的第二个

/html/body

打印百度热搜中第6个的新闻,正确选择标签,可以正确打印


这里找第11个新闻,但是百度热搜中并没有这个
java
WebElement element = driver.findElement(
By.xpath("//*[@id=\"hotsearch-content-wrapper\"]/li[11]/a/span[2]"));
这里会出现找不到标签问题

NoSuchElementException问题
1.元素复制错误
2.页面中不存在
3.代码未加载处来,代码已经执行完了
这里出错以后,自动化打开的浏览器不会自动关闭,可以将复制的xPath在这个页面进行搜索看有没有
操作测试对象
点击/提交对象
click()
java
//找到百度一下按钮,进行点击
driver.findElement(By.cssSelector("#chat-submit-button")).click();
//分开写
WebElement element = driver.findElement(By.cssSelector("#chat-submit-button"));
element.click();
java
public class autotest {
public WebDriver driver = null;
//驱动
public void start(){
//打开浏览器驱动
//System.setProperty("webdriver.chrome.driver", "D:/chrome/chromedriver.exe");
WebDriverManager.chromedriver().setup();
//添加配置
ChromeOptions options = new ChromeOptions();
//运行访问所有连接
options.addArguments("--remote-allow-origins=*");
driver = new ChromeDriver(options);
}
//结束驱动
public void end(){
driver.quit();
}
public void test(){
start();
driver.get("https://www.baidu.com/");
driver.findElement(By.cssSelector("#chat-submit-button")).click();
end();
}
}
启动
java
public class runtest {
public static void main(String[] args) throws InterruptedException {
autotest test = new autotest();
test.test();
}
}
这里可以正常进行页面跳转

但是如果点击页面中不存在的元素 (被隐藏的 )会怎样
此时这里点击这个,页面中并没有显示其对应的元素,此时这个被隐藏了

这里就会出错

java
public void test(){
start();
driver.get("https://www.baidu.com/");
//找这里页面中被隐藏的元素
driver.findElement(By.cssSelector("#s_index_off_css")).click();
end();
}
这里出现了元素不可以交互 的异常

模拟输入
sendKeys("")
模拟按键输入
选择输入框,输入文本
java
//找出对应输入框,输入对应文本即可
driver.findElement(By.cssSelector("#chat-textarea")).sendKeys("输入文本");
java
public void test(){
start();
driver.get("https://www.baidu.com/");
//输入时崎狂三
driver.findElement(By.cssSelector("#chat-textarea")).sendKeys("时崎狂三");
//点击百度一下
WebElement element = driver.findElement(By.cssSelector("#chat-submit-button"));
element.click();
end();
}
选择这个输入 "时崎狂三" ,并点击百度一下

如果连续多个sendKeys()呢?
java
public void test(){
start();
driver.get("https://www.baidu.com/");
driver.findElement(By.cssSelector("#chat-textarea")).sendKeys("时崎狂三");
driver.findElement(By.cssSelector("#chat-submit-button")).click();
driver.findElement(By.cssSelector("#chat-textarea")).sendKeys("五河士道");
driver.findElement(By.cssSelector("#chat-submit-button")).click();
end();
}
这里我们想要的是先搜素 '时崎狂三" 再进行搜素"五河士道",但是输入框中为两个的拼接

因此对同一个文本框进行二次输入需要清除输入框中的内容
清除文本内容
clear()
输⼊⽂本后⼜想换⼀个新的关键词,这⾥就需要⽤到 clear()清除输入框内容
java
public void test() throws InterruptedException {
start();
driver.get("https://www.baidu.com/");
driver.findElement(By.cssSelector("#chat-textarea")).sendKeys("时崎狂三");
Thread.sleep(1000);
driver.findElement(By.cssSelector("#chat-textarea")).clear();
driver.findElement(By.cssSelector("#chat-textarea")).sendKeys("五河士道");
driver.findElement(By.cssSelector("#chat-submit-button")).click();
end();
}
这里将前一次输入的内容清除了,重新进行了输入,最终结果就是最后一次对这个文本框的输入

获取文本信息
getText() 获取文本
获取百度热搜新文标题

java
public void test(){
start();
driver.get("https://www.baidu.com/");
//获取
String text = driver.findElement(By.xpath("//*[@id=\"hotsearch-content-wrapper\"]/li[1]/a/span[2]")).getText();
System.out.println("text:"+text);
end();
}


如何获取到输入框中的默认信息呢

java
public void test(){
start();
driver.get("https://www.baidu.com/");
String text = driver.findElement(By.xpath("//*[@id=\"chat-textarea\"]")).getText();
System.out.println("text:"+text);
end();
}
这里明明有内容为什么为空呢?

因为这里getText()是获取文本 ,但是这里内容是在标签中,也就是属性值

获取属性值需要使用getAttribute("属性名")
java
public void test(){
start();
driver.get("https://www.baidu.com/");
String text = driver.findElement(By.xpath("//*[@id=\"chat-textarea\"]")).getAttribute("data-ai-placeholder");
System.out.println("text:"+text);
end();
}

这里获取内容不同,是因为百度搜素中默认搜素是不断变化的

获取页面标签和当前页面的URL
这里通过getTitle()获取标题,getCurrentUrl()获取当前页面的URL
java
public void test(){
start();
driver.get("https://www.baidu.com/");
String title = driver.getTitle();
String url = driver.getCurrentUrl();
System.out.println("title:"+title);
System.out.println("url:"+url);
end();
}


java
public void test(){
start();
driver.get("https://www.baidu.com/");
//跳转之前
String title = driver.getTitle();
String url = driver.getCurrentUrl();
System.out.println("跳转之前");
System.out.println("title:"+title);
System.out.println("url:"+url);
driver.findElement(By.cssSelector("#chat-textarea")).sendKeys("时崎狂三");
driver.findElement(By.cssSelector("#chat-submit-button")).click();
System.out.println("跳转之后");
String title2 = driver.getTitle();
String url2 = driver.getCurrentUrl();
System.out.println("title:"+title2);
System.out.println("url:"+url2);
end();
}

搜索关键词之后,其对应页面的标题和URL发生改变

上面这是在同一窗口下,覆盖了上一级的页面
如果是新的窗口打开呢?
这里点击百度新闻,会新开一个窗口
java
public void test(){
start();
driver.get("https://www.baidu.com/");
//跳转之前
String title = driver.getTitle();
String url = driver.getCurrentUrl();
System.out.println("跳转之前");
System.out.println("title:"+title);
System.out.println("url:"+url);
driver.findElement(By.cssSelector("#s-top-left > a:nth-child(1)")).click();
String title2 = driver.getTitle();
String url2 = driver.getCurrentUrl();
System.out.println("title:"+title2);
System.out.println("url:"+url2);
end();
}


此时这里的确跳转到了新的窗口,但是这里标题和URL没有改变,此时程序中识别窗口方式不同
窗口
上面这里打开了一个新的窗口,但是Title 和 URL没有改变,还是前一个页面的
在程序中它并不知道当前最新的窗口是那个,每个窗口都有唯一属性句(handle)来表⽰,此时切换窗口,需要切换句柄
切换窗口
java
driver.getWindowHandle();//当前页面句柄
driver.getWindowHandles();//获取所有句柄
driver.switchTo().window(handle);//切换到handle这个句柄
java
public void test(){
start();
driver.get("https://www.baidu.com/");
//跳转之前
String title = driver.getTitle();
String url = driver.getCurrentUrl();
System.out.println("跳转之前");
System.out.println("title:"+title);
System.out.println("url:"+url);
//打开百度新文(新窗口)
driver.findElement(By.cssSelector("#s-top-left > a:nth-child(1)")).click();
String curHandle = driver.getWindowHandle();//当前页面句柄
Set<String> allHandles = driver.getWindowHandles();//获取所有句柄
System.out.println("当前页面句柄:" + curHandle);
System.out.println("所有页面句柄:" + allHandles);
//切换窗口
for(String handle : allHandles){
//切换到另一个句柄,从首页 -> 百度新闻
if(!handle.equals(curHandle)){
driver.switchTo().window(handle);
}
}
System.out.println("跳转之后");
System.out.println("跳转后的句柄:" + driver.getWindowHandle());
String title2 = driver.getTitle();
String url2 = driver.getCurrentUrl();
System.out.println("title:"+title2);
System.out.println("url:"+url2);
end();
}
这里将这个将页面跳转到了最新的页面(切换句柄 )
title和url都有更新

关闭窗口
driver.close()关闭当前窗口
driver.quit();关闭浏览器
java
public void test(){
start();
driver.get("https://www.baidu.com/");
//点击百度新闻,打开一个新的标签页
driver.findElement(By.cssSelector("#s-top-left > a:nth-child(1)")).click();
//将百度首页标签页关闭
driver.close();
//此时还有百度新闻标签页
System.out.println(driver.getCurrentUrl());
end();
}

这里打开了百度新闻在一个新窗口,关闭百度首页窗口,此时进行获取当前窗口失败,为什么呢?这里明明还有百度新闻窗口
因为我们窗口关闭之后,将其句柄切换,这样后续操作才会在当前窗口,否则还是原始窗口

在关闭之后,将其句柄进行切换
java
public void test(){
start();
driver.get("https://www.baidu.com/");
//点击百度新闻,打开一个新的标签页
driver.findElement(By.cssSelector("#s-top-left > a:nth-child(1)")).click();
String curHandle = driver.getWindowHandle();//当前页面句柄
Set<String> allHandles = driver.getWindowHandles();//获取所有句柄
System.out.println("当前页面句柄:" + curHandle);
System.out.println("所有页面句柄:" + allHandles);
for(String handle : allHandles){
//切换到另一个句柄,从首页 -> 百度新闻
if(!handle.equals(curHandle)){
//将百度首页标签页关闭
driver.close();
driver.switchTo().window(handle);
}
}
//此时还有百度新闻标签页
System.out.println(driver.getCurrentUrl());
driver.quit();
}

设置窗口大小
java
//窗口最大化
driver.manage().window().maximize();
//窗口最小化
driver.manage().window().minimize();
//窗口全屏
driver.manage().window().fullscreen();
//手动设置窗口大小
driver.manage().window().setSize(new Dimension(1024,768));
java
public void test() throws InterruptedException {
start();
driver.get("https://www.baidu.com/");
//窗口最大化
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(new Dimension(1024,768));
driver.quit();
}
屏幕截图
java
File file = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(file,new File("test.png"));
java
public void test() throws IOException {
//屏幕截图
start();
driver.get("https://www.baidu.com/");
File file = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(file,new File("test.png"));
end();
}


等待
代码执行速度通常比页面加载快,有时候可能出现页面有些元素未加载而代码执行到了下一步导致错误,此时这里就需要等待页面加载出来再进行操作
强制等待
java
Thread.sleep(3000);
这里百度搜索"时崎狂三"强制等待3秒钟,再点击百度一下
java
public void test() throws InterruptedException {
start();
driver.get("https://www.baidu.com/");
driver.findElement(By.cssSelector("#chat-textarea")).sendKeys("时崎狂三");
Thread.sleep(30000);
driver.findElement(By.cssSelector("#chat-submit-button")).click();
end();
}
优点:使用简单,调试比较有效
缺点:影响运行效率,浪费时间,因为这里强制等待,可能上一步操作时间<3秒,这样就会有时间浪费
隐式等待
隐式等待是一种智能等待,在规定查找元素,指定超时时间内不断查找元素,如果找到就继续执行后续代码,如果超时没有找到元素才会报错
java
implicitlyWait()
//参数:Duration类中提供的毫秒、秒、分钟等方法
//例如:最长等待5s钟
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5));
java
public void test() throws InterruptedException {
start();
driver.get("https://www.baidu.com/");
driver.findElement(By.cssSelector("#chat-textarea")).sendKeys("时崎狂三");
//Thread.sleep(3000);
//隐式等待
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5));
driver.findElement(By.cssSelector("#chat-submit-button")).click();
end();
}
隐式等待作用域整个脚本的所有元素,只要driver对象没有被释放(driver.quit()),隐式等待一直生效
优点:智能等待,作用全局
局限性:作用于页面中所有元素,页面之外的元素(像弹窗这种不属于页面元素)
显示等待
显示等待也是超时时间等待,在指定超时时间范围内只要满足操作的条件就会执行后续代码
new WebDriverWait(driver, Duration.ofSeconds(3)).until($express)
$express:涉及到ExpectedConditions这个类
例如:
java
//显示等待
WebDriverWait wait = new WebDriverWait(driver,Duration.ofSeconds(3));
//等到对应标签内容加载出来才会执行后面代码
wait.until(ExpectedConditions.presenceOfElementLocated(By.xpath("//*[@id=\"1\"]/div/div[1]/div/div[2]/div/div[1]/div/div/div[2]/div[1]")));
java
public void test() throws InterruptedException {
start();
driver.get("https://www.baidu.com/");
driver.findElement(By.cssSelector("#chat-textarea")).sendKeys("时崎狂三");
driver.findElement(By.cssSelector("#chat-submit-button")).click();
//Thread.sleep(3000);
//隐式等待
//driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5));
//显示等待
WebDriverWait wait = new WebDriverWait(driver,Duration.ofSeconds(3));
//等到对应标签内容加载出来才会执行后面代码
wait.until(ExpectedConditions.presenceOfElementLocated(By.xpath("//*[@id=\"1\"]/div/div[1]/div/div[2]/div/div[1]/div/div/div[2]/div[1]")));
end();
}
搜索时崎狂三,等其这里第一个视频元素加载出来

ExpectedConditions类下的方法
presenceOfElementLocated(Bylocator):检查页面上DOM 上是否存在元素。
textToBe(Bylocator,String str):检查元素
java
//显示等待
WebDriverWait wait = new WebDriverWait(driver,Duration.ofSeconds(3));
//百度
wait.until(ExpectedConditions.textToBe(By.xpath("//*[@id=\"s-top-left\"]/a[1]"),"新闻"));
等标题加载出来
java
wait.until(ExpectedConditions.titleIs("title"))
java
public void test() throws InterruptedException {
start();
driver.get("https://www.baidu.com/");
driver.findElement(By.cssSelector("#chat-textarea")).sendKeys("时崎狂三");
driver.findElement(By.cssSelector("#chat-submit-button")).click();
//显示等待
WebDriverWait wait = new WebDriverWait(driver,Duration.ofSeconds(3));
//等标题加载出来
wait.until(ExpectedConditions.titleIs("时崎狂三_百度搜索"));
end();
}
等这里标题title加载出来


java
//这里页面标题不对,这里就会等到超时时间
wait.until(ExpectedConditions.titleIs("时崎狂三"));
超出时间未能找到这个标题 ,也给出了当前标题

java
//可以使用这个,标题中包含"时崎狂三"即可
wait.until(ExpectedConditions.titleContains("时崎狂三"));
url包含baidu即可
java
wait.until(ExpectedConditions.urlContains("baidu"));
优点:是智能等待,可以自定义显示等待条件,操作灵活
缺点:写法相较于隐式等待复杂一点
但是如果既有显示等待又有隐式等待 同时等待同一个元素
这里等待一个不存在的元素最终等待的时间是多少
java
public void test(){
start();
//隐式等待设置为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("#hotsearch-content-wrapper > li:nth-child(1) > a > span.title-contentaaa")));
}catch (Exception e){
System.out.println("nosuelement!");
}
System.out.println(sim.format(System.currentTimeMillis()));
end();
}
这里等待了11s左右,既有显示等待,又有隐式等待,我们不知道等待多长时间,因此这里最好不要两个等待同时等待同一个
不要混合隐式和显式等待,可能会导致不可预测的等待时间
浏览器导航
打开网站
这两个方法都可以进行浏览器打开网站
java
driver.navigate().to("https://www.baidu.com/");
driver.get("https://www.baidu.com/");
浏览器的前进、后退、刷新
java
public void test() throws InterruptedException {
start();
driver.navigate().to("https://www.baidu.com/");
//driver.get("https://www.baidu.com/");
//百度 "时崎狂三"
driver.findElement(By.cssSelector("#chat-textarea")).sendKeys("时崎狂三");
driver.findElement(By.cssSelector("#chat-submit-button")).click();
Thread.sleep(1000);
//后退百度首页
driver.navigate().back();
Thread.sleep(1000);
//前进到结果页
driver.navigate().forward();
Thread.sleep(1000);
//页面刷新
driver.navigate().refresh();
end();
}

弹窗
有3种类型弹窗


像这种弹窗,不是页面上的元素,无法用元素选择器进行选择,需要使用到对应窗口操作

警告弹窗
html
<html>
<head>
</head>
<body>
<a id="tooltip" href="#" data-toggle="tooltip" onclick="window.alert("Sample alert")">See an example alert</a>
</body>
</html>
<html>
<head>
</head>
<body>


java
public void test() throws InterruptedException {
start();
//警告弹窗网页
driver.get("file:///D:/JAVA/selenium-html/alert.html");
//触发弹窗
driver.findElement(By.cssSelector("#tooltip")).click();
//切换到警告弹窗
Alert alert = driver.switchTo().alert();
//获取弹窗上文本
String txt = alert.getText();
System.out.println("alertText:" + txt);
Thread.sleep(3000);
//点击确认按钮
alert.accept();
//alert.dismiss();
}
这里虽然只有确认按钮,但是如何使用dismiss点击取消按钮,这里也是可以的

确认弹窗
html
<html>
<head>
<script type="text/javascript">
function disp_confirm()
{
var r=confirm("Press a button")
if (r==true)
{
document.write("You pressed OK!")
}
else
{
document.write("You pressed Cancel!")
}
}
</script>
</head>
<body>
<input type="button" onclick="disp_confirm()"
value="Display a confirm box" />
</body>
</html>

java
public void test() throws InterruptedException {
start();
//确认弹窗网页
driver.get("file:///D:/JAVA/selenium-html/confirm.html");
//触发弹窗
driver.findElement(By.cssSelector("body > input[type=button]")).click();
//切换到弹窗上
Alert alert = driver.switchTo().alert();
//获取弹窗上文本
String txt = alert.getText();
System.out.println("alertText:" + txt);
Thread.sleep(3000);
//点击取消按钮
alert.dismiss();
//刷新页面,选择确认按钮
driver.navigate().refresh();
//触发弹窗
driver.findElement(By.cssSelector("body > input[type=button]")).click();
alert = driver.switchTo().alert();//切换弹窗可以不重复切换,即使当前页面触发了多次弹窗
Thread.sleep(3000);
//点击取消按钮
alert.accept();
}
第二次弹窗切换是同一个弹窗,可以不用切换
java
//可以省略,如果是同一个弹窗
alert = driver.switchTo().alert();//切换弹窗可以不重复切换,即使当前页面触发了多次弹窗
点击取消按钮

点击确认按钮

提示弹窗
html
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script type="text/javascript">
function disp_prompt() {
var name = prompt("Please enter yourname", "")
if (name != null && name != "") {
document.write("Hello " + name + "!")
}
}
</script>
</head>
<body>
<input type="button" onclick="disp_prompt()" value="请点击" />
</body>
</html>

这里有文本框,可以进行输入
java
public void test() throws InterruptedException {
start();
driver.get("file:///D:/JAVA/selenium-html/Prompt.html");
driver.findElement(By.cssSelector("body > input[type=button]")).click();
//切换到弹窗
Alert alert = driver.switchTo().alert();
//获取弹窗上文本
String txt = alert.getText();
System.out.println("alert_txt:" + txt);
Thread.sleep(2000);
//点击取消按钮
alert.dismiss();
//刷新页面
driver.navigate().refresh();
//触发弹窗
driver.findElement(By.cssSelector("body > input[type=button]")).click();
//同一个弹窗,alert可以不变
//alert = driver.switchTo().alert();
//输入文本
alert.sendKeys("时崎狂三");
Thread.sleep(3000);
alert.accept();
}

强制等待和显示等待都可以处理等待弹窗问题,而隐式等待不可以

java
public void test() throws InterruptedException {
start();
//访问博客网址
driver.get("http://47.108.157.13:8090/blog_login.html");
//输入用户名
driver.findElement(By.cssSelector("#username")).sendKeys("zhangsan");
//输入密码
driver.findElement(By.cssSelector("#password")).sendKeys("1");
//点击登录按钮
driver.findElement(By.cssSelector("#submit")).click();
// //强制等待
// Thread.sleep(3000);
// //隐式等待
// driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(3));
//显示等待
WebDriverWait wait = new WebDriverWait(driver,Duration.ofSeconds(3));
wait.until(ExpectedConditions.alertIsPresent());
//弹窗处理
Alert alert = driver.switchTo().alert();
System.out.println(alert.getText());
alert.accept();
driver.quit();
}
显示等待
这里是等这里弹窗出来,才可以对弹窗进行后续操作

java
//隐式等待
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(3));
这里等待页面中元素都加载出来,但这里后续对弹窗操作,却说没有弹窗,弹窗并不属于页面元素,隐式等待等的是页面上元素,所以弹窗相关等待使用显示等待

java
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>upload_file</title>
<script type="text/javascript">
</script>
</head>
<body>
<div class="row-fluid">
<div class="span6 well">
<h3>upload_file</h3>
<input type="file" name="file" />
</div>
</div>
</body>
</html>
选择文件进行上传

但是发现一个问题,就是这里系统的,文件管理系统,并不属于页面,这里如何进行选择文件上传呢?
java
public void test() throws InterruptedException {
start();
driver.get("file:///D:/JAVA/selenium-html/upload.html");
Thread.sleep(3000);
//这里直接选择文件路径进行上传
driver.findElement(By.cssSelector("body > div > div > input[type=file]")).sendKeys("D:/test");
Thread.sleep(3000);
driver.quit();
}
这里html较为简单,直接选择对应文件路径就可以

浏览器参数设置
设置无头模式
java
//无头模式相当于后台进程,这里并不会将浏览器打开页面展示出来
options.addArguments("-headless");
java
public void test(){
//打开浏览器驱动
System.setProperty("webdriver.chrome.driver", "D:/chrome/chromedriver.exe");
//WebDriverManager.chromedriver().setup();
//添加配置
ChromeOptions options = new ChromeOptions();
//运行访问所有连接
options.addArguments("--remote-allow-origins=*");
//设置无头模式
options.addArguments("-headless");
driver = new ChromeDriver(options);
driver.get("https://www.baidu.com/");
driver.quit();
}
浏览器加载策略
https://www.selenium.dev/documentation/webdriver/drivers/options/#pageloadstrategy


normal : 默认策略 。它会等待页面所有资源(如HTML、CSS、图片、脚本等)都完成加载,即页面完全加载完毕
eager :只等待初始的HTML文档(DOM)被完全解析并准备就绪 ,可以交互,但像图片或样式表等其他资源可能仍在加载中
none :此策略完全不会阻塞 WebDriver 的执行 ,WebDriver 会立即开始执行命令,而不等待页面加载,可以导致要操作元素还未加载出来
java
public void test(){
//打开浏览器驱动
System.setProperty("webdriver.chrome.driver", "D:/chrome/chromedriver.exe");
//WebDriverManager.chromedriver().setup();
//添加配置
ChromeOptions options = new ChromeOptions();
//运行访问所有连接
options.addArguments("--remote-allow-origins=*");
//设置无头模式
//options.addArguments("-headless");
//options.setPageLoadStrategy(PageLoadStrategy.NONE);
options.setPageLoadStrategy(PageLoadStrategy.EAGER);
// options.setPageLoadStrategy(PageLoadStrategy.NORMAL);
driver = new ChromeDriver(options);
driver.get("https://www.baidu.com/");
driver.quit();
}