《手把手教你》系列技巧篇(二十四)-java+ selenium自动化测试-三大延时等待(详细教程)
1.简介
前边讲解完八大元素定位大法,今天宏哥讲解和分享一下三大延时等待。宏哥这里简称“三等八定”。很多人在群里问,这个下拉框定位不到、那个弹出框定位不到…各种定位不到,其实大多数情况下就是两种问题:1. 有frame,2. 没有加等待。殊不知,你的代码运行速度是什么量级的,而浏览器加载渲染速度又是什么量级的,就好比闪电侠和凹凸曼约好去打怪兽,然后闪电侠打完回来之后问凹凸曼你为啥还在穿鞋没出门?凹凸曼分分中内心一万只羊驼飞过,欺负哥速度慢,哥不跟你玩了,抛个异常撂挑子了。 那么怎么才能照顾到凹凸曼缓慢的加载速度呢?只有一个办法,那就是等喽。说到等,又有三种等法,且听宏哥一一道来。
2.为啥要等待?
有时候我们做自动化测试,需要等待。因为我们的下一步执行依赖于上一步的执行结果,因为程序执行的是很快的,上一步执行完毕马上执行下一步,有时候上一步的结果还没加载出来,下一步就执行了,这样就会造成错误,比如No suchElement Exception有时候就是因为这样造成的。 我们经常会碰到用selenium操作页面上某个元素的时候,需要等待页面加载完成后, 才能操作。 否则页面上的元素不存在,会抛出异常。 或者碰到AJAX异步加载,我们需要等待元素加载完成后,才能操作。在进行UI自动化测试时,需要等元素加载完成,才能对元素进行操作,不然找不到元素会报错,因此需要增加等待在上篇selenium+java元素定位的使用中。
3.Selenium的三大等待
3.1硬性等待(sleep)
先讲强制等待,大家应该都不会陌生,sleep就是强制等待。硬性等待也称为强制等待、线程休眠。强制等待,顾名思义就是强迫你等待呗,你等也得等不等也得等,没有商量。不管页面是否加载完,强制指定等待时间后继续执行。不建议用这种方式。此种等待方法直接调用Thread.sleep()方法来进行线程等待,由于此方法较为死板,不够灵活,会导致脚本运行时间变长,故建议尽量少用
Thread.sleep():固定休眠时间设置,Java的Thread类里提供了休眠方法sleep,导入包后就能使用
sleep()方法以毫秒为单位
只要在case中加入sleep就会强制等待设置的时间后才会执行之后的命令,这种等待一般适用于调试脚本的时候。
java代码,采用方式如下:
Thread.sleep(3000);----------表示线程等待3秒,执行到此时不管什么就固定的等待三秒之后再接着执行后面的操作。
封装方法如下:
public static void wait(int second){
try {
Thread.sleep(second*3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
优缺点 :硬性等待使用简单,但由于不知道一个线程需要等待多久,时间设置小了不行,设置长了往往会造成时间的浪费,影响性能。
3.2隐式等待(ImplicitlyWait)
implicitlyWait()方法比sleep()方法智能,sleep()方法只能在一个固定的时间等待,而implicitlyWait()可以在一个时间范围内等待,称为隐式等待。
隐式等待,是设置的全局等待。设置等待时间,是对页面中的所有元素设置加载时间,如果元素不是马上就能定位成功就会在固定等待时长内不停去搜索元素,在设置时间内发现元素则执行后面操作,如果超出了设置的时间还没发现元素则抛出异常。隐式等待可以理解成在规定的时间范围内,浏览器在不停的刷新页面,直到找到相关元素或者时间结束。
隐式等待采用全部设置,也就是说,你所有的findElement方法都会隐式等待10s,java代码,采用方式如下:
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
----此方法针对执行脚本的所有对象,等待10秒
timeouts()---->驱动超时对象,该对象可以进行多种场景的等待超时设置,而implicitlyWait即为隐式等待,会在设置的时间内不停查找元素或超时
隐式等待一般是在driver初始化之后设置,只用设置一次,全局生效可用,只适用于找元素findElement方法,其它方法没有等待效果,找到元素后就停止了,如果找到元素的时间大于设置的时间,则报一个找不到元素的异常。
此处共有三个方法,分别为查找元素的等待超时时间、页面加载等待超时时间和js脚本运行超时时间,方法如下代码所示:
System.setProperty("webdriver.chrome.driver", "D:\\test\\driver\\chromedriver.exe");
ChromeDriver chrome = new ChromeDriver();
//此处为设定页面加载超时时间为30s
chrome.manage().timeouts().pageLoadTimeout(30, TimeUnit.SECONDS);
//此处为设定元素查找最长超时时间为10s
chrome.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
//此处为设置js脚本运行超时时间为30s
chrome.manage().timeouts().setScriptTimeout(30, TimeUnit.SECONDS);
优缺点 :隐式等待相对灵活,但是设置是针对全局的,并不是所有的元素都需要等待,也不能适用条件更复杂的情况,如元素肉眼不可点击,元素不可见时不能用
3.3显式等待(Explicit wait)
显示等待是等待指定元素设置的等待时间,在设置时间内,默认每隔0.5s检测一次当前的页面这个元素是否存在,如果在规定的时间内找到了元素则执行相关操作,如果超过设置时间检测不到则抛出异常。默认抛出异常为:NoSuchElementException。做自动化的时候推荐使用显示等待。
显式等待的意思,就是判断这个元素是否加载完成,如果在规定的时间加载完成就进行下一步操作,如果在规定的时间没有加载完成就抛出异常。显式等待通常是自定义的一段代码,用来等待某个条件发生后再继续执行后续代码。此种方式用于特定元素、特定条件的等待,使用灵活,建议使用这种方法来进行等待设置。
【场景1:登录一个网站,输入用户名和密码后,点击登录,需要加载好几秒钟才能进入用户中心。例如你登录你网银,用户名和密码验证通过后,它需要等几秒,才能显示你账户信息,这几秒,它需要去 数据库 查询数据并显示在前端。 场景2:你登录一个旅行网站,填好了出发起点和目的地,点击搜索,需要查询等待几秒,然后给你显示车票信息。】
例子1:自带的条件
显式等待每隔一段时间扫描一次页面,检查元素是否满足结果条件,检查元素是否存在,不存在则继续等待,直到找到或超时, 该方式不是全局设置 ,推荐使用
当页面的某些元素需要鼠标放上去才展示出来时,显示等待的presenceoOfElementLocatde方法相当隐式等待,不可直接点击,需要配合鼠标操作才可点击
例2:自定义条件
自定义条件需要自定义我们需要等待的条件
4.实战
前边文章中都用到过强制和隐式等待了,没有用到过显示等待,那么宏哥就在这里给小伙伴后者童鞋们来演示一下,以便更好的区分和理解。
实例:打开百度首页面“更多”下拉页面里的音乐页面。
4.1测试用例
1.具体测试用例: (1)打开百度首页 (2)鼠标移动到首页的“更多” (3)等待出现“查看百度全部产品” (4)定位音乐图标并点击 (5)获取新打开页面的title,进行断言
4.2代码设计
根据测试用例进行代码设计如下图所示:
4.3参考代码
参考代码如下:
package lessons;
import junit.framework.Assert;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
* @author 北京-宏哥
* 《手把手教你》系列技巧篇(二十一)-java+ selenium自动化测试-三大延时等待(详细教程)
* 2021年8月18日
public class TestMusic {
@SuppressWarnings("deprecation")
public static void main(String [] args) throws InterruptedException {
System.setProperty("webdriver.gecko.driver", ".\\Tools\\chromedriver.exe"); //指定驱动路径
WebDriver driver = new ChromeDriver ();
//最大化窗口
//driver.manage().window().maximize();
//打开百度首页
driver.get("http://wwww.baidu.com");
//声明一个Action对象
Actions action=new Actions(driver);
//鼠标移动到 更多产品 上
action.moveToElement(driver.findElement(By.xpath("//a[text()='更多']"))).perform();
//显示等待时间10s 等 全部产品>> 出现
WebDriverWait w=new WebDriverWait(driver,10);
w.until(ExpectedConditions.presenceOfAllElementsLocatedBy(By.xpath("//a[text()='查看全部百度产品 >']")));
//等待的元素出现后点击 音乐
WebElement cp=driver.findElement(By.xpath("//a/div[text()='音乐']"));
cp.click();
//断言音乐页面的Title值为 千千音乐-听见世界
Assert.assertEquals("千千音乐-听见世界",driver.getTitle());
System.out.println("断言通过!");
}
4.4运行代码
1.运行代码,右键Run AS->java Application,控制台输出,如下图所示:
2.运行代码后电脑端的浏览器的动作,如下小视频所示:
3.浏览器实现结果,宏哥怕大家不注意视频后浏览器实现结果,因此专门截图,如下图所示:
通过浏览器的实现结果,和代码的运行结果,可以判断出: 即使web页面已跳转至新窗口,但是代码逻辑还在原有窗口
为解决该问题,我们需要引入 句柄 的概念: 窗口句柄 ,粗略的理解,每个窗口对应一个句柄,句柄可认为是一个唯一长字符串
有了前边宏哥上下两卷的窗口切换的介绍,想必你知道这是怎么回事了吧,那么解决此问题的方法就是不是相当简单了,只需要切换一下窗口,进行断言即可!
4.5优化后的参考代码
package lessons;
import junit.framework.Assert;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
* @author 北京-宏哥
* 《手把手教你》系列技巧篇(二十四)-java+ selenium自动化测试-三大延时等待(详细教程)
* 2021年8月28日
public class TestMusic {
public static void main(String [] args) throws InterruptedException {
System.setProperty("webdriver.gecko.driver", ".\\Tools\\chromedriver.exe"); //指定驱动路径
WebDriver driver = new ChromeDriver ();
//最大化窗口
driver.manage().window().maximize();
//打开百度首页
driver.get("http://wwww.baidu.com");
//声明一个Action对象
Actions action=new Actions(driver);
//鼠标移动到 更多产品 上
action.moveToElement(driver.findElement(By.xpath("//a[text()='更多']"))).perform();
//显示等待时间10s 等 全部产品>> 出现
WebDriverWait w=new WebDriverWait(driver,10);
w.until(ExpectedConditions.presenceOfAllElementsLocatedBy(By.xpath("//a[text()='查看全部百度产品 >']")));
//等待的元素出现后点击 音乐
WebElement cp=driver.findElement(By.xpath("//a/div[text()='音乐']"));
cp.click();
//切换至新窗口
//首先,我们要先获取到一个主句柄,作为灯塔,防止"迷路"
String mainWindow = driver.getWindowHandle();
//接着我们要获取所有的句柄信息,并赋值给 handles
//String[] handles=new String[driver.getWindowHandles().size()];
//String handles = driver.getWindowHandles();
System.out.println("切换前的title:"+driver.getTitle());
//使用for循环,遍历所有的handles,以便判断
for (String temphandle:driver.getWindowHandles()){
if(!temphandle.equals(mainWindow))
driver.close();
driver.switchTo().window(temphandle);
//让我们打印一下当前窗口的 title
System.out.println("切换后的title:"+driver.getTitle());
//断言音乐页面的Title值为 千千音乐-听见世界