本节重点
- 元素定位
- 操作测试对象
- 窗⼝
- 等待
- 导航
- 弹窗
- ⽂件上传
- 浏览器参数
1.元素的定位
web⾃动化测试的操作核⼼是能够找到⻚⾯对应的元素,然后才能对元素进⾏具体的操作。
常⻅的元素定位⽅式⾮常多,如id,classname,tagname,xpath,cssSelector
常⽤的主要由cssSelector和xpath
1.1 cssSelector
选择器的功能:选中⻚⾯中指定的标签元素
选择器的种类分为基础选择器和复合选择器,常⻅的元素定位⽅式可以通过id选择器和⼦类选择器来进⾏定位。

定位百度⾸⻚的"百度热搜"元素,可以使⽤通过id选择器和⼦类选择器进⾏定位:#s-hotsearch
wrapper > div
"搜索输⼊框元素":#kw
"百度⼀下按钮":#su

1.2 xpath
XML路径语⾔,不仅可以在XML⽂件中查找信息,还可以在HTML中选取节点。
xpath使⽤路径表达式来选择xml⽂档中的节点
xpath语法中:
1.2.1 获取HTML⻚⾯所有的节点
//*
1.2.2 获取HTML⻚⾯指定的节点
//[指定节点]
//ul :获取HTML⻚⾯所有的ul节点
//input:获取HTML⻚⾯所有的input节点
1.2.3 获取⼀个节点中的直接⼦节点
/
//span/input
1.2.4 获取⼀个节点的⽗节点
..
//input/.. 获取input节点的⽗节点
1.2.5 实现节点属性的匹配
@...
//*[@id='kw'] 匹配HTML⻚⾯中id属性为kw的节点
1.2.6 使⽤指定索引的⽅式获取对应的节点内容
注意:xpath的索引是从1开始的。
百度⾸⻚通过://div/ul/li[3] 定位到第三个百度热搜标签
更便捷的⽣成selector/xpath的⽅式:右键选择复制"Copy selector/xpath"
注意:元素的定位⽅法必须唯⼀。
案例:如果想要匹配到百度⾸⻚指定的新闻⽂本或者节点集:,直接使⽤ #hotsearch-content
wrapper > li 能够满⾜吗?
回答:不能满足。必须指定到选择哪一个新闻,后面需要加上:nth-child(i)
#hotsearch-content-wrapper > li:nth-child(5) > a
问题:既然可以⼿动复制 selector/xpath的⽅式 ,为什么还有了解语法?
⼿动复制的selector/xpath表达式并不⼀定满⾜上⾯的唯⼀性的要求,有时候也需要⼿动的进⾏修改表达式
案例:百度⾸⻚(需要登陆百度账号)右侧的热搜,复制li标签下的a标签,复制好的的selector为: #title-content ,xpath为: //*[@id="title-content"] ,可以⼿动操作⼀下,⼿动复制的表达式是否唯⼀呢?
2.操作测试对象
获取到了⻚⾯的元素之后,接下来就是要对元素进⾏操作了。常⻅的操作有点击、提交、输⼊、清
除、获取⽂本。
2.1 点击/提交对象
click()
driver .findElement(By.cssSelector("#su")).click();
注意:除了按钮之外,页面的绝大部分元素都是可以点击的,但是一些页面隐藏的标签、不可见的标签就不能点击
第一步:筛选:看标签type是否有hidden关键字
第二步:看每个标签对应的样式
2.2 模拟按键输⼊
sendKeys("")
driver .findElement(By.cssSelector("#kw")).sendKeys("输⼊⽂字");
2.3 清除⽂本内容
输⼊⽂本后⼜想换⼀个新的关键词,这⾥就需要⽤到 clear()
driver .findElement(By.cssSelector("#kw")).sendKeys("我爱游戏");
driver.findElement(By.cssSelector("#kw")).clear();
driver .findElement(By.cssSelector("#kw")).sendKeys("我爱学习");
2.4 获取⽂本信息
如果判断获取到的元素对应的⽂本是否符合预期呢?获取元素对应的⽂本并打印⼀下~~
获取⽂本信息: getText()
java
public void test04() throws InterruptedException {
createDriver();
List<WebElement> ll=driver.findElements(By.cssSelector("#hotsearch-content-wrapper > li> a > span.title-content-title")) ;
for (WebElement wb:ll) {
System.out.println(wb.getText());
}
driver.quit();
}

问题:是否可以通过 getText() 获取到"百度⼀下按钮"上的⽂字"百度⼀下"呢?尝试⼀下
回答:不可以。因为百度一下实质上是该按钮的value值,是属性而不是元素值。

注意:⽂本和属性值不要混淆了。获取属性值需要使⽤⽅法 getAttribute("属性名称") ;
java
public void test05() throws InterruptedException {
createDriver();
WebElement ll=driver.findElement(By.cssSelector("#su")) ;
System.out.println(ll.getAttribute("value"));
driver.quit();
}
2.5 获取当前⻚⾯标题
getTitle()
2.6获取当前⻚⾯URL
getCurrentUrl()
3.窗⼝
打开⼀个新的⻚⾯之后获取到的title和URL仍然还是前⼀个⻚⾯的?
当我们⼿⼯测试的时候,我们可以通过眼睛来判断当前的窗⼝是什么,但对于程序来说它是不知道当前最新的窗⼝应该是哪⼀个。对于程序来说它怎么来识别每⼀个窗⼝呢?每个浏览器窗⼝都有⼀个唯⼀的属性句柄(handle)来表⽰,我们就可以通过句柄来切换
3.1 切换窗⼝
1)获取当前⻚⾯句柄:
driver.getWindowHandle();
2)获取所有⻚⾯句柄:
driver.getWindowHandles();
3)切换当前句柄为最新⻚⾯:
java
public void test10() throws InterruptedException {
createDriver();
String windowHandle = driver.getWindowHandle();
System.out.println(windowHandle);
WebElement we=driver.findElement(By.cssSelector("#s-top-left > a:nth-child(1)"));
we.click();
Set<String> windowHandles = driver.getWindowHandles();
for (String i:windowHandles) {
if (i!=windowHandle) {
driver.switchTo().window(i);
}
}
driver.findElement(By.cssSelector("#headline-tabs > ul > li > a"));
System.out.printf("title:"+driver.getTitle());
Thread.sleep(3000);
driver.quit();
}
注意:执⾏了driver.close()之前需要切换到未被关闭的窗⼝
3.2 窗⼝设置⼤⼩
1)窗⼝的⼤⼩设置
java
public void test09() throws InterruptedException {
createDriver();
WebElement we=driver.findElement(By.cssSelector("#kw"));
we.sendKeys("刘宇");
driver.findElement(By.cssSelector("#su")).click();
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(new Dimension(1624,728));
Thread.sleep(3000);
driver.quit();
}
3.3 窗⼝切换
去掉等待后,获取跳转后的⻚⾯元素失败
// 获取所有句柄
// 获取当前停留⻚⾯句柄
java
public void test10() throws InterruptedException {
createDriver();
String windowHandle = driver.getWindowHandle();
System.out.println(windowHandle);
WebElement we=driver.findElement(By.cssSelector("#s-top-left > a:nth-child(1)"));
we.click();
Set<String> windowHandles = driver.getWindowHandles();
for (String i:windowHandles) {
if (i!=windowHandle) {
driver.switchTo().window(i);
}
}
driver.findElement(By.cssSelector("#headline-tabs > ul > li > a"));
System.out.printf("title:"+driver.getTitle());
Thread.sleep(3000);
driver.quit();
}
3.4 屏幕截图
我们的⾃动化脚本⼀般部署在机器上⾃动的去运⾏,如果出现了报错,我们是不知道的,可以通过抓拍来记录当时的错误场景
屏幕截图⽅法需要额外导⼊包:
File file = ((TakesScreenshot)webDriver).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(file,new File(filename));
代码演⽰
java
//简单版本
File srcfile = driver.getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(srcfile,new File("my.png"));
这里提出了新的要求:
1)每次生成的屏幕截图都能保存下来,避免覆盖
2)屏幕截图文件统一放到test下的image文件夹下
3)生成的屏幕截图名称,要见名知义---即看到这个屏幕截图我就知道是哪个测试方法的屏幕截图
java
public void getshot(String str) throws IOException {
SimpleDateFormat sim1=new SimpleDateFormat("yyyy-MM-dd");
SimpleDateFormat sim2=new SimpleDateFormat("HHmmss");
String dirTime=sim1.format(System.currentTimeMillis());
String fileTime=sim2.format(System.currentTimeMillis());
String filename="./src/test/img/"+dirTime+"/"+str+"-"+fileTime+".png";
File srcShot= ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(srcShot,new File(filename));
}
3.5关闭窗⼝
driver.close();
注意:该方法使用场景较少,只有当当前标签页要关掉,重新操作原先标签页才需要,记得窗⼝关闭后driver要重新定义
假如写自动化代码出现了NoSuchElement错误
第一步:在报错的代码前添加Thread.sleep(秒),设置的时间长一点
第二步:执行自动化,在自动化打开的页面里打开前端开发者工具,手动检査元素是否真的不存在
1)自动化打开的页面确实不存在该元素
--手动打开的页面和自动化打开的页面不一样(很可能是登陆和未登录状态下页面不一样) --元素为动态元素
解决方法:先定位动态元素的前一级标签,再增加要定位的元素标签
2)自动化打开的页面确实存在该元素
代码执行的速度比页面消染的速度要快,页面还没消染出来,程序已经开始找了,导致元素没有找到
解决办法----添加等待
4、等待
通常代码执⾏的速度⽐⻚⾯渲染的速度要快,如果避免因为渲染过慢出现的⾃动化误报的问题呢?可以使⽤selenium中提供的三种等待⽅法:
4.1 强制等待
Thread.sleep()
优点:使⽤简单,直接阻塞程序,调试的时候⽐较有效
缺点:影响运⾏效率,浪费⼤量的时间
4.2 隐式等待
隐式等待是⼀种智能等待,他可以规定在查找元素时,在指定时间内不断查找元素。如果找到则代码-继续执⾏,直到超时没找到元素才会报错。
implicitlyWait() 参数:Duration类中提供的毫秒、秒、分钟等⽅法
⽰例:
java
//隐式等待1000毫秒
driver.manage().timeouts().implicitlyWait(Duration.ofMillis(1000));
//隐式等待5秒
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5));
隐式等待作⽤域是整个脚本的所有元素。即只要driver对象没有被释放掉(driver.quit()),隐式等待就⼀直⽣效。
优点:智能等待,作⽤于全局
缺点:只能查找元素,每次查找元素都要等待,不能查找弹窗
4.3 显⽰等待
显⽰等待也是⼀种智能等待,在指定超时时间范围内只要满⾜操作的条件就会继续执⾏后续代码
new WebDriverWait(driver, Duration.ofSeconds(3)).until($express)
$press:涉及到selenium.support.ui.ExpectedConditions包下的ExpectedConditions类
返回值:boolean
⽰例:
java
public void test14() throws InterruptedException, IOException {
createDriver();
WebDriverWait webDriverWait = new WebDriverWait(driver, Duration.ofSeconds(2));
webDriverWait.until(ExpectedConditions.elementToBeClickable(By.cssSelector("#su")));
driver.findElement(By.cssSelector("#su")).click();
webDriverWait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("#kw")));
driver.findElement(By.cssSelector("#kw")).sendKeys("dilireba");
webDriverWait.until(ExpectedConditions.textToBe(By.cssSelector("#s-top-left > a:nth-child(1)"), "新闻"));
driver.close();
}
ExpectedConditions预定义⽅法的⼀些⽰例:
• elementToBeClickable(By locator) ‒ ⽤于检查元素的期望是可⻅的并已启⽤,以便您可以单击它。
• textToBe(Bylocator,String str) - 检查元素。(精确匹配)
• presenceOfElementLocated(Bylocator) ‒ 检查⻚⾯的 DOM 上是否存在元素。
• urlToBe(java.lang.String url) ‒ 检查当前⻚⾯的 URL 是⼀个特定的 URL。
优点:显⽰等待是智能等待,可以⾃定义显⽰等待的条件,操作灵活
缺点:写法复杂
隐式等待和显⽰等待⼀起使⽤效果如何呢?
测试⼀下
java
//隐式等待设置为5s,显⽰等待设置为10s,那么结果会是5+10=15s吗?
SimpleDateFormat sim =new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(sim.format(System.currentTimeMillis()));
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5));
driver.findElement(By.cssSelector("#hotsearch-content-wrapper > li:nth
child(1) > a > span.title-content"));
WebDriverWait wait = new WebDriverWait(driver,Duration.ofSeconds(10));
try{
wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("#hotsear
ch-content-wrapper > li:nth-child(1) > a > span.title-content")));
}catch (Exception e){
System.out.println("nosuelement!");
}
System.out.println(sim.format(System.currentTimeMillis()));
结果:重试多次,最终打印的等待时间有10s、11s....
结论:不要混合隐式和显式等待,可能会导致不可预测的等待时间。
5.浏览器导航
常⻅操作:
1)打开⽹站
// 更⻓的⽅法
driver.navigate().to("https://selenium.dev");
// 简洁的⽅法
driver.get("https://selenium.dev");
2)浏览器的前进、后退、刷新
driver.navigate().back();
driver.navigate().forward();
driver.navigate().refresh();
案例:百度⾸⻚测试https://tool.lu/标签⼊⼝
6. 弹窗
弹窗是在⻚⾯是找不到任何元素的,这种情况怎么处理?使⽤selenium提供的Alert接⼝
6.1 警告弹窗+确认弹窗

Alert alert = driver.switchTo.alert();
//确认
alert.accept()
//取消
alert.dismiss()
6.2 提⽰弹窗

Alert alert = driver.switchTo.alert();
alert.sendKeys("hello");
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)设置⽆头模式

无头模式:在后台执行,不会显示打开浏览器,看不到效果
2)设置浏览器加载策略
options.setPageLoadStrategy(PageLoadStrategy.NONE);
注意:存在网页的特殊情况,手动打开页面立即渲染,但通过自动化打开却很慢,甚至超过隐式时间等待
