Selenium是web应用中基于UI的自动化测试框架。
支持多平台、多浏览器、多语言。
通过上图,我们可以注意到3个角色,下面具体讲解一下:
- 自动化脚本:对于java来说也就是使用WebDriver API编写的测试脚本。用于发送给浏览器驱动。
- 浏览器的驱动(browser driver):每个浏览器都有自己的驱动,均以exe文件形式存在。比如谷歌的chromedriver.exe、火狐的geckodriver.exe、IE的IEDriverServer.exe。它来解析这些自动化测试的代码,解析后把它们发送给浏览器。
- 浏览器:浏览器当然就是我们很熟悉的常用的各种浏览器。执行浏览器驱动发来的指令,并最终完成工程师想要的操作。
结合上图,我们可以进一步理解:
- 对于每一条Selenium脚本,一个http请求会被创建并且发送给浏览器的驱动。
- 浏览器驱动中包含了一个HTTP Server,用来接收这些http请求。
- HTTP Server接收到请求后根据请求来具体操控对应的浏览器。
- 浏览器执行具体的测试步骤。
- 浏览器将步骤执行结果返回给HTTP Server。
- HTTP Server又将结果返回给Selenium的脚本,如果是错误的http代码我们就会在控制台看到对应的报错信息。
- Chrome浏览器。下载地址:https://www.google.cn/intl/zh-CN/chrome/
- Chrome的驱动(ChromeDriver)。注意驱动版本要和你的Chrome浏览器版本对应起来。下载地址:https://chromedriver.chromium.org/downloads
- Selenium3工具包。maven仓库导入依赖:https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java/3.141.59
编写第一个Selenium的Demo:
public static void main(String[] args) throws InterruptedException {
// 创建浏览器驱动
WebDriver webDriver = new ChromeDriver();
// 访问百度
webDriver.get("https://www.baidu.com");
}
元素的定位应该是自动化测试的核心,要想操作一个对象,首先应该识别这个对象,webdriver 提供 findElement()
、findElements()
两种方法搭配对象定位方法进行元素定位。webdriver 提供了一系列的对象定位方法:id、name、class name、link text、partial link text、tag name、xpath、css selector,我们实际测试中比较常用的主要有两种:
css定位是基于css选择器的,我们可以通过查找页面中的选择器定位页面元素内容。比如常见的有id选择器:#id、类选择器:.class、标签选择器:标签名、后代选择器:父标签 子标签。
XPath 是一种在XML 文档中定位元素的语言。功能比较强大,但是语法比较复杂,如果想要系统学习,推荐网站 W3school,这里大致介绍一下它的基本使用:
使用绝对路径定位元素:
/html/head/title
整个表达式的含义是从文档的根元素开始,选择其子元素 html,再选择子元素 head,最后选择 head 元素下的子元素 title相对路径+索引:
//form/span[1]/input
这个表达式表示从根节点开始,找到所有名为“form”的元素,然后在每个form元素中找到第一个span元素,并在该span元素下找到input元素。这种方法使用了索引,以确切指定所需元素的位置。相对路径+属性值:
//input[@class="s_ipt"]
此XPath表达式用于选择所有标签名为input且class属性的值为"s_ipt"的元素。@符号用于引用属性,这样就可以根据属性值来定位元素。相对路径+通配符:
//[@="su"]
这个XPath表达式使用通配符*来选择文档中所有包含属性名包含指定字符串“su”的元素。这种方法可以用来定位具有特定属性的元素,而不关心具体是哪种元素。相对路径+文本匹配:
//a[text()="新闻"]
该表达式选择所有标签名为a且文本内容为“新闻”的元素。在括号内使用text()函数来指定需要匹配的文本内容。
如果主要任务是在Web开发中定义样式和布局,那么CSS选择器会更加适合;而如果需要进行复杂的XML文档处理或需要更精细的节点定位,XPath选择器则更为合适。另外CSS选择器是专门为HTML文档设计的,浏览器在解析和渲染HTML页面时会针对CSS选择器进行高效的优化。
PS:在实际的测试中可以打开开发者工具使用选择页面元素,鼠标右键即可快速得到元素的 css/xpath 的定位。
click()
点击对象sendKeys()
在对象上模拟按键输入clear()
清除对象中输入的内容submit()
对象提交
注:如果点击的元素放在 form 标签中,此时使用 submit 实现的效果和 click 是一样的;如果点击的元素放在非 form 标签中,此时使用 submit 会报错。
public class Main {
public static void main(String[] args) throws InterruptedException {
// 创建浏览器驱动
WebDriver webDriver = new ChromeDriver();
// 访问百度
webDriver.get("https://www.baidu.com");
sleep(1000);
// 在输入框模拟键盘输入
webDriver.findElement(By.cssSelector("#kw")).sendKeys("csdn不摸鱼的程序员");
sleep(1000);
// 点击"百度一下"
webDriver.findElement(By.cssSelector("#su")).click();
sleep(1000);
// 清除输入框
webDriver.findElement(By.cssSelector("#kw")).clear();
sleep(1000);
// 点击第一条搜索结果
webDriver.findElement(By.cssSelector("#\\31 > div > div:nth-child(1) > h3 > a")).click();
}
}
结果展示:
在上述代码中我们已经用到了 sleep()
,sleep() 是强制等待,它会根据里面的时间参数进行等待。
public class ImplicitlyWaitExample {
public static void main(String[] args) {
WebDriver driver = new ChromeDriver();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); // 设置隐式等待时间为10秒
driver.get("https://www.example.com");
// 后续操作
// ...
driver.quit();
}
}
在上述示例中,我们使用 driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS)
来设置隐式等待时间为10秒。这样,在查找元素或执行命令时,WebDriver会等待一定的时间直到元素出现或超时为止。
注意事项:
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS)
被放置在创建ChromeDriver实例之后,但是在执行任何实际的测试步骤之前。这确保了在整个测试过程中都会应用隐式等待设置,以便在查找元素时进行等待。值得注意的是,隐式等待仅需要设置一次,通常在WebDriver实例创建后立即设置即可。在整个测试执行过程中,这个设置会对后续的元素查找操作生效,直到WebDriver实例被关闭或隐式等待设置被清除为止。
public class WebDriverWaitExample {
public static void main(String[] args) {
WebDriver driver = new ChromeDriver();
driver.get("https://www.example.com");
// 使用显式等待等待元素可点击
WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement button = wait.until(ExpectedConditions.elementToBeClickable(By.id("myButton")));
button.click();
// 后续操作
// ...
driver.quit();
}
}
在上述示例中,我们使用了 WebDriverWait
结合 ExpectedConditions
,等待直到特定的条件 发生后再继续执行。在这里,我们等待元素可点击后再进行点击操作
getText()
方法用于获取网页元素显示的文本内容,通常指的是元素内部的可见文本。getAttribute()
方法用于获取元素的指定属性的值,比如id、name、class等。
public static void main(String[] args) throws InterruptedException {
// 创建浏览器驱动
WebDriver webDriver = new ChromeDriver();
// 访问百度
webDriver.get("https://www.baidu.com");
sleep(1000);
// 获取百度词条文本
String text = webDriver.findElement(
By.cssSelector("#hotsearch-content-wrapper > li:nth-child(1) > a > span.title-content-title")).getText();
System.out.println("元素内文本:"+text);
sleep(1000);
// 获取输入框name
String name = webDriver.findElement(By.cssSelector("#kw")).getAttribute("name");
System.out.println("元素属性 name:"+name);
}
getCurrentUrl()
方法用于获取当前浏览器所在页面的 URL 地址。
getTitle()
方法用于获取当前页面的标题,即页面标签()中的文本内容。
public static void main(String[] args) throws InterruptedException {
// 创建浏览器驱动
WebDriver webDriver = new ChromeDriver();
// 访问百度
webDriver.get("https://www.baidu.com");
sleep(1000);
// 获取百度url
String url = webDriver.getCurrentUrl();
System.out.println("百度 url:"+url);
sleep(1000);
// 获取百度title
String title = webDriver.getTitle();
System.out.println("百度 title:"+title);
}
click()
点击: 模拟鼠标左键单击操作,可以用于点击链接、按钮或其他可交互的元素。doubleClick()
双击: 模拟鼠标左键双击操作,可以用于特定的双击交互场景。contextClick()
右键点击: 模拟鼠标右键单击操作,可以触发上下文菜单或其他右键交互效果。moveToElement()
悬停: 将鼠标移动到指定的元素上并悬停,可以用于触发显示悬停菜单或者提示信息。dragAndDrop()
拖放: 模拟鼠标拖动操作,通常用于实现拖放交互效果。
Actions类代表用户交互的动作,它用于构建和执行用户在网页上的鼠标、键盘等操作。
public static void main(String[] args) throws InterruptedException {
// 创建浏览器驱动
WebDriver driver = new ChromeDriver();
// 访问百度
driver.get("https://www.baidu.com");
sleep(1000);
// 获取到百度一下按钮
WebElement element = driver.findElement(By.cssSelector("#su"));
// 初始化 action
Actions actions = new Actions(driver);
// 点击操作
actions.click(element).perform();
sleep(1000);
// 获取底部元素
WebElement element1 = driver.findElement(By.cssSelector("#bottom_layer > div > p:nth-child(8)"));
// 双击操作
actions.doubleClick(element1).perform();
sleep(1000);
// 获取“图片”文字
WebElement element2 = driver.findElement(By.cssSelector("#s-top-left > a:nth-child(6)"));
// 右键点击操作
actions.contextClick(element2).perform();
sleep(1000);
// 获取到百度logo
WebElement element3 = driver.findElement(By.cssSelector("#lg > map > area"));
// 悬停操作
actions.moveToElement(element3).perform();
sleep(1000);
// 模拟拖放操作(从底部移动到顶部)
WebElement sourceElement = driver.findElement(By.cssSelector("#bottom_layer > div > p:nth-child(1) > a"));
WebElement targetElement = driver.findElement(By.cssSelector("#s-top-left > a:nth-child(1)"));
actions.dragAndDrop(sourceElement, targetElement).perform();
sleep(1000);
actions.click().perform();
sleep(1000);
}
PS:在 Selenium 中,perform()
方法用于执行之前定义的动作序列。当你使用Actions类构建了一系列的鼠标或键盘操作时,这些操作并不会立即执行,而是将它们放入了一个动作序列中。只有当调用perform()方法时,Selenium才会按照你定义的顺序执行这些操作。这种设计方式的好处在于你可以构建复杂的鼠标和键盘操作序列,然后一次性执行它们。
- sendKeys(Keys.TAB) // TAB
- sendKeys(Keys.ENTER) // 回车
- sendKeys(Keys.SPACE) // 空格键
- sendKeys(Keys.ESCAPE) // 回退键(Esc)
- sendKeys(Keys.CONTROL,“a”) // 全选(Ctrl+A)
- sendKeys(Keys.CONTROL,“c”) // 复制(Ctrl+C)
- sendKeys(Keys.CONTROL,“x”) // 剪贴(Ctrl+X)
- sendKeys(Keys.CONTROL,“v”) // 粘贴(Ctrl+V)
public static void main(String[] args) throws InterruptedException {
// 创建浏览器驱动
WebDriver driver = new ChromeDriver();
// 访问百度
driver.get("https://www.baidu.com");
sleep(2000);
// 获取到百度搜索框
WebElement element = driver.findElement(By.cssSelector("#kw"));
// 输入内容-》输入空格-》输入内容-》输入TAP-》输入内容-》回车键
element.sendKeys("不摸鱼");
sleep(1000);
element.sendKeys(Keys.SPACE);
sleep(1000);
element.sendKeys("的");
sleep(1000);
element.sendKeys(Keys.TAB);
sleep(1000);
element.sendKeys("程序员");
sleep(1000);
element.sendKeys(Keys.ENTER);
// 全选-》剪贴-》粘贴
element.sendKeys(Keys.CONTROL,"a");
sleep(1000);
element.sendKeys(Keys.CONTROL,"x");
sleep(1000);
element.sendKeys(Keys.CONTROL,"v");
sleep(1000);
}
webDriver.navigate().forward()
:这条语句是用于让浏览器向前导航,即转到浏览历史中的下一个页面。webDriver.navigate().back()
:与forward()相反,该语句用于使浏览器返回到浏览历史中的上一个页面。webDriver.manage().window().maximize()
:这是用来最大化浏览器窗口的操作。webDriver.manage().window().setSize(new Dimension(width, height))
:该语句用于设置浏览器窗口的大小。你可以指定所需的宽度和高度参数,从而调整浏览器窗口的大小,适应不同的测试场景或需求。window.scrollTo(0, document.body.scrollHeight)
Js脚本,实现滚动到页面底部。(第一个参数是水平滚动位置,第二个参数是垂直滚动位置)window.scrollTo(0, 0)
Js脚本,实现滚动到页面顶部。
public static void main(String[] args) throws InterruptedException {
// 创建浏览器驱动
WebDriver driver = new ChromeDriver();
// 访问百度
driver.get("https://www.baidu.com");
sleep(2000);
// 获取到百度搜索框
WebElement element = driver.findElement(By.cssSelector("#kw"));
// 搜索“软件测试”
element.sendKeys("软件测试");
sleep(1000);
element.sendKeys(Keys.ENTER);
sleep(1000);
// 返回百度首页
driver.navigate().back();
sleep(1000);
// 返回软件测试搜索页
driver.navigate().forward();
sleep(1000);
// 自定义浏览器窗口
driver.manage().window().setSize(new Dimension(500,500));
sleep(1000);
// 实现浏览器窗口最大化
driver.manage().window().maximize();
sleep(1000);
// 实现滚动到页面底部
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("window.scrollTo(0, document.body.scrollHeight)");
sleep(1000);
// 实现滚动到页面顶部
js.executeScript("window.scrollTo(0, 0)");
sleep(1000);
}
Alert弹窗、确认框(Confirm)、提示框(Prompt):
switchTo().alert()
:用于切换到页面上的警告框,并返回一个Alert对象,你可以使用这个对象来接受、取消或者输入文本到警告框中。alert.accept()
:用于接受警告框(点击“确定”按钮)。alert.dismiss()
:用于取消警告框(点击“取消”按钮)。alert.sendKeys("your_text")
:用于在警告框中输入文本。
下面就以Prompt提示框为例进行演示:
public static void main(String[] args) throws InterruptedException {
// 创建浏览器驱动
WebDriver webDriver = new ChromeDriver();
// 访问
webDriver.get("http://localhost:63342/autoTest/src/main/page/alert.html?_ijt=g52rrlh3gfrag8ivs5g3ec40c0");
sleep(1500);
// 点击弹窗按钮
webDriver.findElement(By.cssSelector("body > button")).click();
sleep(1000);
// 切换到页面上的警告框
Alert alert = webDriver.switchTo().alert();
// 点击取消
alert.dismiss();
sleep(1000);
// 再次点击按钮
webDriver.findElement(By.cssSelector("body > button")).click();
sleep(1000);
// 输入“不摸鱼”
alert = webDriver.switchTo().alert();
alert.sendKeys("不摸鱼");
sleep(1000);
// 点击确定
alert.accept();
sleep(1000);
}
单选按钮(Radio Button)操作:
- 通过WebElement对象来处理单选按钮。
click()
:单击选择单选按钮。
复选框(Checkbox)操作:
- 通过WebElement对象来处理复选框。
click()
:单击以切换复选框的选中状态。
public static void main(String[] args) throws InterruptedException {
// 创建浏览器驱动
WebDriver webDriver = new ChromeDriver();
// 访问
webDriver.get("http://localhost:63342/autoTest/src/main/page/choice.html?_ijt=fc7i1795ada371afdv81v0iqk2");
sleep(1500);
// 选择并点击2/3两个复选框
WebElement box1 = webDriver.findElement(By.cssSelector("#c2"));
box1.click();
sleep(1000);
WebElement box2 = webDriver.findElement(By.cssSelector("#c3"));
box2.click();
sleep(1000);
// 选择第二个单选框
WebElement choice = webDriver.findElement(By.cssSelector("#r2"));
choice.click();
sleep(1000);
}
通过Select类来处理下拉框:
selectByVisibleText("visible_text")
:根据下拉选项的可见文本进行选择。selectByValue("value")
:根据下拉选项的值进行选择。selectByIndex(index)
:根据下拉选项的索引进行选择(从0开始)。
public static void main(String[] args) throws InterruptedException {
// 创建浏览器驱动
WebDriver webDriver = new ChromeDriver();
// 访问
webDriver.get("http://localhost:63342/autoTest/src/main/page/pulldown.html?_ijt=bjk05362bbitst3j1nrntnnrn9");
sleep(1500);
// 定位下拉框按钮
WebElement shippingMethod = webDriver.findElement(By.name("ShippingMethod"));
sleep(1000);
// 定义select对象
Select select = new Select(shippingMethod);
// 根据索引选择第3个
select.selectByIndex(2);
sleep(1000);
// 根据属性孩子选择value=11.61
select.selectByValue("11.61");
sleep(1000);
}
WebElement.sendKeys()
:这是用于将文件路径发送到 input 元素的方法。你可以找到file input元素,然后调用sendKeys()方法并传递文件的绝对路径作为参数,以便实现文件上传操作。
public static void main(String[] args) throws InterruptedException, IOException {
// 创建浏览器驱动
WebDriver webDriver = new ChromeDriver();
// 访问
webDriver.get("http://localhost:63342/autoTest/src/main/page/upload.html?_ijt=bhatof5910d1h8q6675j3jjoa5");
sleep(1500);
// 上传图片
WebElement uploadFile = webDriver.findElement(By.cssSelector("body > input[type=file]"));
uploadFile.sendKeys("D:\\博客图片\\MyBlog\\java.png");
sleep(1000);
}
截图操作需要导入Commons-io依赖:https://mvnrepository.com/artifact/commons-io/commons-io/2.11.0
然后调用 TakesScreenshot
接口中的 getScreenshotAs()
方法:
public static void main(String[] args) throws InterruptedException, IOException {
// 创建浏览器驱动
WebDriver webDriver = new ChromeDriver();
// 访问
webDriver.get("https://www.baidu.com");
sleep(1500);
// 搜索“不摸鱼的程序员”
webDriver.findElement(By.cssSelector("#kw")).sendKeys("不摸鱼的程序员-csdn");
webDriver.findElement(By.cssSelector("#su")).click();
sleep(3000);
// 截图
File file = ((TakesScreenshot)webDriver).getScreenshotAs(OutputType.FILE);
// 将图片保存到硬盘
FileUtils.copyFile(file, new File("D://20231111.png"));
}
在 web 页面中如果使用到iframe框架,则不能直接对框架内部的元素进行定位,需要先切换到对应的iframe在进行定位操作:
webDriver.switchTo().frame()
:这是Selenium中用于切换到指定iframe的主要方法。你可以通过索引、ID、名称或WebElement对象来指定要切换到的iframe。webDriver.switchTo().parentFrame()
:当你需要从iframe返回到其上一级的上下文时,可以使用这个方法。webDriver.switchTo().defaultContent()
:如果你需要从所有嵌套的iframes中返回到最外层的页面上下文,可以使用这个方法。
public static void main(String[] args) throws InterruptedException, IOException {
// 创建浏览器驱动
WebDriver webDriver = new ChromeDriver();
// 访问
webDriver.get("http://localhost:63342/autoTest/src/main/page/iframe.html?_ijt=hiqvtbuga50aga3831ql9nu2ph");
sleep(1500);
// 切换到 iframe:f1
webDriver.switchTo().frame("f1");
// 点击内部的click
webDriver.findElement(By.cssSelector("body > div > div > a")).click();
sleep(1000);
}
在讲解多窗口定位前,我们先了解一下 窗口句柄:
窗口句柄是一个在操作系统级别用于标识窗口的唯一标识符。在Selenium中,窗口句柄通常用于标识浏览器窗口或标签页,并且允许我们在多个窗口之间进行切换和操作。当你在浏览器中打开一个新的标签页或窗口时,每个窗口都有自己的唯一句柄。通过获取这些句柄,Selenium可以帮助你跟踪和管理不同的窗口,从而实现在多个窗口之间进行切换、定位元素和执行操作的功能。
Selenium 中提供了如下api用于操作窗口:
- 获取当前窗口句柄:使用driver.getWindowHandle()方法可以获取当前窗口的句柄。
- 获取所有窗口句柄:使用driver.getWindowHandles()方法可以获取所有打开窗口的句柄。
- 切换窗口:使用driver.switchTo().window(windowHandle)方法可以切换到指定的窗口。
public static void main(String[] args) throws InterruptedException, IOException {
// 创建浏览器驱动
WebDriver webDriver = new ChromeDriver();
// 访问百度(注:此时窗口句柄在百度首页,webDerive的所有操作只能针对首页)
webDriver.get("https://www.baidu.com");
sleep(1500);
// 打开百度图片窗口
webDriver.findElement(By.cssSelector("#s-top-left > a:nth-child(6)")).click();
sleep(1000);
// 先将窗口句柄切换到百度图片窗口
// 1.获取所有窗口句柄
Set<String> windowHandles = webDriver.getWindowHandles();
// 2.找到最后一个句柄即为百度图片窗口句柄
String imageHHandle = "";
for (String handle : windowHandles) {
imageHHandle = handle;
}
// 3.切换到百度图片窗口
webDriver.switchTo().window(imageHHandle);
// 点击百度图片窗口中的头像标签
webDriver.findElement(By.cssSelector("#wrapper_head_box > div > div > div > div > div.hotquery > a:nth-child(3)")).click();
sleep(1000);
}
webDriver.close()
关闭当前聚焦的浏览器窗口,不会清空会话和缓存。webDriver.quit()
关闭所有的浏览器窗口,会清空会话和缓存。
public static void main(String[] args) throws InterruptedException, IOException {
// 创建浏览器驱动
WebDriver webDriver = new ChromeDriver();
// 访问百度(注:此时窗口句柄在百度首页,webDerive的所有操作只能针对首页)
webDriver.get("https://www.baidu.com");
String mainHandle = webDriver.getWindowHandle(); // 获取首页句柄
sleep(1500);
// 打开百度图片窗口
webDriver.findElement(By.cssSelector("#s-top-left > a:nth-child(6)")).click();
sleep(1500);
// 切换到主页(这个操作只是为了将显示页面切换到首页,句柄还是首页)
webDriver.switchTo().window(mainHandle);
sleep(1500);
// 打开百度贴吧窗口
webDriver.findElement(By.cssSelector("#s-top-left > a:nth-child(4)")).click();
sleep(1500);
// 关闭当前聚焦页面(注:由于此时窗口句柄为百度首页,所以此时close()会关闭首页,而不是百度图片页)
webDriver.close();
sleep(1500);
// 关闭浏览器
webDriver.quit();
}