前言
在熟悉了元素定位之后,我们接下来就要学习对定位到的元素进行操作这项内容了。我简要做了个总结,如下图:

1 基本操作
元素的基本操作有很多,常用的有三个:click(点击)、clear(清空)、sendkeys(输入内容)、submit(提交)。何为基本操作,即这些方法在WebElement接口类中定义,通过实例化的WebElement直接调用。
void click():单击目标元素。void submit():提交当前form(表单)内容到远程服务器,注意是特定于表单元素而言的。void sendKeys(CharSequence... keysToSend):使用此方法模拟键入元素,这可能会设置元素的值。一般是对文本输入元素进行此操作,否则会报错org.openqa.selenium.ElementNotInteractableException: element not interactablevoid clear():如果此元素是文本输入元素(INPUT型元素和TEXTAREA元素),则将清除该值。对其他元素没有影响。此方法并不会触发鼠标和键盘操作。String getTagName():获取并返回此元素的tagName(String类型)。String getAttribute(String name):获取并返回当前元素的给定属性的值(String类型)。boolean isSelected():确定是否选择了此元素。此操作仅适用于输入元素,如checkboxes(复选框)、options in a select(下拉选择框中的选项) 和radio buttons(单选框按钮)boolean isEnabled():元素当前是否已启用?除了禁用的输入元素之外的内容,通常都会返回true。String getText():获取此元素及子元素的可见(即不被CSS隐藏)内文本,不带任何前导或尾随空格。boolean isDisplayed():是否显示此元素?Point getLocation():获取并返回此元素的左上角在页面上的位置(以一组x,y轴坐标值表示)。Dimension getSize():获取并返回此元素的高度和宽度(一对整型像素值,如332,450)Rectangle getRect():呈现元素的位置和大小。String getCssValue(String propertyName):获取并返回此元素给定CSS属性的值(String类型)
2 select操作
select,即下拉选择框,这类元素的操作一般是选中select中的某一项,selenium中的Select类提供了很多对select元素的操作方法。
首先,从Select类的有参构造函数可以看出,在初始化一个select时,需要WebElement作为入参。接下来,我们看看,Select类提供了哪些函数吧。
首先,我们最关心的当然是,下拉选择的相关方法,其中单选3个方法:
void selectByVisibleText(String text):使用可见文本来选中某一项void selectByIndex(int index):使用索引来选中某一项void selectByValue(String value):使用value来选中某一项
相对应的,多选也有4个方法(当然多选需要select标签的multiple属性的值为multiple):
void deselectAll():选中所有项void deSelectByVisibleText(String text):使用可见文本来选中某一项。void deSelectByIndex(int index):使用索引来选中某一项。void deSelectByValue(String value):使用value来选中某一项。
另外,还提供一些其他方法:
boolean isMultiple():此select元素的multiple属性的值是否为multiple?List<WebElement> getOptions():返回此select元素所有的项。List<WebElement> getAllSelectedOptions():返回此select元素所有选中状态的项的集合。WebElement getFirstSelectedOption():返回此select元素第一个选中状态的项。setSelected(WebElement option, boolean select):使得此select元素的某项被点击(从而被选中),这个方法是下拉选择的相关方法的核心实现方法。
下面用一个实例演示一下select的操作。
示例代码-select-1:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>UI自动化测试页面</title>
</head>
<body>
<div id="div"><select id="city" multiple="multiple"><option value="">请选择一个城市</option><option value="010" selected>北京</option><option value="021">上海</option><option value="0571">杭州</option></select>
</div>
</body>
</html>
实现代码-select-1:
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.support.ui.Select;/*** @author muguozheng* @date 2020/4/18 17:56* @Description: 元素定位测试* @modify*/
public class ElementTest {public static void main(String[] args) {// 指定浏览器驱动的路径String driverPath = "E:/source/driver/chromedriver_80_2.exe";System.setProperty("webdriver.chrome.driver", driverPath);// 创建一个chrome driverWebDriver driver = new ChromeDriver();// 页面最大化driver.manage().window().maximize();try {// 访问测试页面-路径改成自己的driver.get("file:///E:/project/automation/src/test/java/test.html");// 获取select元素WebElement element = driver.findElement(By.cssSelector("#city"));// 实例化一个selectSelect select = new Select(element);select.selectByVisibleText("上海");// 增加延时以便观察Thread.sleep(3000);select.selectByIndex(3);Thread.sleep(3000);select.selectByValue("010");Thread.sleep(5000);} catch (Exception e) {e.printStackTrace();} finally {driver.quit();}}
}
3 页面跳转
这里的页面跳转是广义上的,包括跳转到window(新页面)、frame、alert弹窗等。在selenium中,是借助switchTo()函数完成的。我们查看源码,发现switchTo()函数的返回值是TargetLocator,这是接口类WebDriver的一个内部接口,这个内部接口定义一系列跳转方法。
这些方法的返回值都是WebDriver,我们可以理解为driver的焦点发生了转移。因此,有一点需要留意,既然焦点转移到了新的页面上,那么想要定位原页面的元素,就要跳转回去。
3.1 frame跳转
WebDriver frame(int index):根据索引获取frameWebDriver frame(String nameOrId):根据name或id获取frameWebDriver frame(WebElement frameElement):根据WebElement(也就是可以用xpath、css等定位到frame元素作为参数)获取frameWebDriver parentFrame():转移焦点到父级内容,如果当前内容是顶级内容,将不发生变化。
下面进行实例演示。
页面代码-frame-1:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>UI自动化测试页面</title>
</head>
<body>
<div id="div"><select id="city"><option value="">请选择一个城市</option><option value="010">北京</option><option value="021">上海</option><option value="0571">杭州</option></select>
</div>
<iframe style="height:1000px;width:100%" id="myIframe" src="http://www.baidu.com"></iframe>
</body>
</html>
实现代码-frame-1:
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.Select;public class ElementTest {public static void main(String[] args) {// 指定浏览器驱动的路径String driverPath = "E:/source/driver/chromedriver_80_2.exe";System.setProperty("webdriver.chrome.driver", driverPath);// 创建一个chrome driverWebDriver driver = new ChromeDriver();// 页面最大化driver.manage().window().maximize();try {// 访问测试页面driver.get("file:///E:/project/automation/src/test/java/test.html");// 跳转到frame// driver.switchTo().frame("myIframe") 通过nameOrId跳转// frame(WebElement frameElement)方式跳转driver.switchTo().frame(driver.findElement(By.xpath("//*[@id='myIframe']")));// 在frame中进一步操作driver.findElement(By.id("kw")).sendKeys("测试");Thread.sleep(3000);// 跳转回父级页面driver.switchTo().parentFrame();Select select = new Select(driver.findElement(By.id("city")));select.selectByValue("010");Thread.sleep(5000);} catch (Exception e) {e.printStackTrace();} finally {driver.quit();}}
}
3.2 窗口跳转
当我们点击了a标签元素时,会触发打开链接页面的事件,有两种情形:
- 在当前窗口加载新页面内容
- 新建一个窗口加载新页面内容,这种情况在
a标签有target="_blank"时触发
当发生第2种情况时,同上文的frame类似,由于driver的焦点还停留在原窗口,我们在新窗口的页面上定位元素时,自然会产生错误,因此引出driver焦点跳转问题。
selenium提供了唯一的窗口跳转方法:WebDriver window(String nameOrHandle),方法的入参nameOrHandle意为窗口名称(name)或句柄(handle),但查看源码和很多资料也没弄清楚窗口的name是什么,只好先研究一下handle了。
通过handle跳转窗口有3种思路:
- 先记录当前窗口句柄记为句柄1(
String getWindowHandle()),打开新页面后获取所有窗口句柄的集合,遍历此集合,与句柄1不同则跳转该句柄所指向的窗口。 - 打开新的页面后获取当前所有窗口句柄(
Set<String> getWindowHandles()),通过索引(越晚打开的窗口,其索引越大)来跳转到目标窗口。 - 打开新的页面后获取当前所有窗口句柄,通过窗口标题(
title)来跳转到目标窗口。
下面通过一个例子来进行演示,我们要实现的场景是:
- 打开【UI自动化测试页面】,点击超链接,在新窗口打开【UI自动化-新页面】。
- 在【UI自动化-新页面】的输入框输入"新页面"。
- 返回【UI自动化测试页面】,在输入框输入【原页面】。
页面代码-window-1:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>UI自动化测试页面</title>
</head>
<body>
<div id="div"><a id="new_page" target="_blank" href="file:///E:/project/58coin/automation/src/test/java/testNew.html">点击跳转新页面</a>
</div>
<div style="margin-top: 10px"><input type="text" id="input">
</div>
</body>
</html>
页面代码-window-2:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>UI自动化-新页面</title>
</head>
<body>
<div><input type="text" id="new_input">
</div>
</body>
</html>
实现代码-window-1(句柄对比方式):
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import java.util.Set;public class ElementTest {public static void main(String[] args) {// 指定浏览器驱动的路径String driverPath = "E:/source/driver/chromedriver_80_2.exe";System.setProperty("webdriver.chrome.driver", driverPath);// 创建一个chrome driverWebDriver driver = new ChromeDriver();// 页面最大化driver.manage().window().maximize();try {// 访问测试页面driver.get("file:///E:/project/automation/src/test/java/test.html");// 获取当前窗口句柄String handlePresent = driver.getWindowHandle();// 点击超链接打开新页面driver.findElement(By.id("new_page")).click();// 遍历句柄集合,与handlePresent不同,则是新窗口,跳转并结束遍历Set<String> handles = driver.getWindowHandles();for (String handle : handles) {if (!handle.equals(handlePresent)) {driver.switchTo().window(handle);break;}}System.out.println("当前页面title:" + driver.getTitle());driver.findElement(By.cssSelector("#new_input")).sendKeys("新页面");Thread.sleep(1000); // 暂停1s以便观察// 跳转到原来窗口driver.switchTo().window(handlePresent);System.out.println("当前页面title:" + driver.getTitle());driver.findElement(By.id("input")).sendKeys("原页面");Thread.sleep(5000);} catch (Exception e) {e.printStackTrace();} finally {driver.quit();}}
}
实现代码-window-2(索引方式):
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;public class ElementTest {public static void main(String[] args) {// 指定浏览器驱动的路径String driverPath = "E:/source/driver/chromedriver_80_2.exe";System.setProperty("webdriver.chrome.driver", driverPath);// 创建一个chrome driverWebDriver driver = new ChromeDriver();// 页面最大化driver.manage().window().maximize();try {// 访问测试页面driver.get("file:///E:/project/automation/src/test/java/test.html");// 点击超链接打开新页面driver.findElement(By.id("new_page")).click();Set<String> winSet = driver.getWindowHandles();//获取所有句柄List<String> winList = new ArrayList<String>(winSet);//转成list列表// 跳转到最新打开的窗口driver.switchTo().window(winList.get(winList.size() - 1));System.out.println("当前页面title:" + driver.getTitle());driver.findElement(By.cssSelector("#new_input")).sendKeys("新页面");Thread.sleep(1000); // 暂停1s以便观察// 跳转到倒数第二个打开的窗口driver.switchTo().window(winList.get(winList.size() - 2));System.out.println("当前页面title:" + driver.getTitle());driver.findElement(By.id("input")).sendKeys("原页面");Thread.sleep(5000);} catch (Exception e) {e.printStackTrace();} finally {driver.quit();}}
}
实现代码-window-3(标题方式):
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import java.util.Set;public class ElementTest {public static void main(String[] args) {// 指定浏览器驱动的路径String driverPath = "E:/source/driver/chromedriver_80_2.exe";System.setProperty("webdriver.chrome.driver", driverPath);// 创建一个chrome driverWebDriver driver = new ChromeDriver();// 页面最大化driver.manage().window().maximize();try {// 访问测试页面driver.get("file:///E:/project/automation/src/test/java/test.html");// 点击超链接打开新页面driver.findElement(By.id("new_page")).click();// 获取窗口句柄的集合(set)Set<String> handles = driver.getWindowHandles();// 遍历并通过title判断目标窗口for (String handle : handles) {if (driver.switchTo().window(handle).getTitle().contains("UI自动化-新页面")) {driver.switchTo().window(handle);break;}}System.out.println("当前页面title:" + driver.getTitle());driver.findElement(By.cssSelector("#new_input")).sendKeys("新页面");Thread.sleep(1000); // 暂停1s以便观察// 遍历并通过title判断目标窗口for (String handle : handles) {if (driver.switchTo().window(handle).getTitle().contains("UI自动化测试页面")) {driver.switchTo().window(handle);break;}}System.out.println("当前页面title:" + driver.getTitle());driver.findElement(By.id("input")).sendKeys("原页面");Thread.sleep(5000);} catch (Exception e) {e.printStackTrace();} finally {driver.quit();}}
}
3.3 alert跳转
alert弹窗本质是js原生代码,不是标签元素,并且一个页面中最多有且仅有一个alert弹窗,如果页面中出现了alert弹窗,一定要先处理它,不然无法进行其他操作。alert弹窗切换的操作非常简单。
Alert接口中提供了以下几个方法:
void dismiss():点击弹窗的取消按钮void accept():点击弹窗的确认按钮String getText():获取弹窗的文本内容void sendKeys(String keysToSend):向弹窗中输入内容
下面演示一个示例:
页面代码-alert-1:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>UI自动化测试页面</title><script type="text/javascript">function display_alert() {alert("I am an alert box!!")}</script>
</head>
<body>
<div><input type="button" id="alert" onclick="display_alert()" value="Display alert box"/><input type="text" id="input">
</div>
</body>
</html>
实现代码-alert-1:
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;public class ElementTest {public static void main(String[] args) {// 指定浏览器驱动的路径String driverPath = "E:/source/driver/chromedriver_80_2.exe";System.setProperty("webdriver.chrome.driver", driverPath);// 创建一个chrome driverWebDriver driver = new ChromeDriver();// 页面最大化driver.manage().window().maximize();try {// 访问测试页面driver.get("file:///E:/project/automation/src/test/java/test.html");// 点击弹窗按钮driver.findElement(By.id("alert")).click();// 弹窗确定:没有这一步处理,后续操作将报错driver.switchTo().alert().accept();// 输入框输入内容driver.findElement(By.id("input")).sendKeys("测试");Thread.sleep(5000);} catch (Exception e) {e.printStackTrace();} finally {driver.quit();}}
}
4 鼠标操作
在selenium中,所有的鼠标操作的实现全部由Actions类提供。首先,Actions类提供了多个有参构造方法:
public Actions(WebDriver driver)
public Actions(Keyboard keyboard, Mouse mouse)
public Actions(Keyboard keyboard)
但后两个构造方法只是扩展方法,很少用。第一个构造方法才是最重要的,它的入参是当前的WebDriver。
再让我们看一下这个类提供了哪些操作鼠标的方法:
Actions clickAndHold(WebElement target):在特定元素上单击鼠标左键(不释放)Actions release(WebElement target):在特定元素上释放鼠标左键Actions doubleClick(WebElement target):在特定元素上双击鼠标左键Actions moveToElement(WebElement target):移动鼠标指针到特定元素Actions contextClick(WebElement target):在特定元素上右键单击Actions dragAndDrop(WebElement source, WebElement target):拖拽元素void perform():执行具体的操作。前面6个方法都是声明一个操作,只有调用perform()后才会真正执行操作。
下面以拖拽元素做一下鼠标操作的演示:
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;public class ElementTest {public static void main(String[] args) {// 指定浏览器驱动的路径String driverPath = "E:/source/driver/chromedriver_80_2.exe";System.setProperty("webdriver.chrome.driver", driverPath);// 创建一个chrome driverWebDriver driver = new ChromeDriver();// 页面最大化driver.manage().window().maximize();try {// 访问测试页面driver.get("https://www.runoob.com/try/try-cdnjs.php?filename=jqueryui-api-droppable");// 跳转到右侧iframedriver.switchTo().frame("iframeResult");WebElement source = driver.findElement(By.id("draggable"));WebElement target = driver.findElement(By.id("droppable"));Actions actions = new Actions(driver);actions.dragAndDropBy(source, 110, 120).perform();Thread.sleep(2000); // 延时以观察效果actions.dragAndDrop(source, target).perform();Thread.sleep(5000);} catch (Exception e) {e.printStackTrace();} finally {driver.quit();}}
}
5 键盘操作
对于键盘的模拟操作,Actions 类中有提供 keyUp(CharSequence key)、keyDown(CharSequence key)、sendKeys(CharSequence key) 等方法来实现。
另外在Keys类中,提供了很多模拟按键,如BACK_SPACE、ENTER等。
对于普通键盘,使用 sendKeys(CharSequence key) 就可以实现:
Actions action = new Actions(driver);
action.sendKeys(Keys.BACK_SPACE);// 模拟按下并释放 BACK_SPACE键
action.sendKeys(Keys.ENTER);// 模拟按下并释放回车键
而对于修饰键,在 WebDriver 中需要用到 KeyDown(theKey)、keyUp(theKey) 方法来操作。
Actions action = new Actions(driver);
action.keyDown(Keys.CONTROL);// 按下 Ctrl 键
action.keyDown(Keys.SHIFT);// 按下 Shift 键
action.keyDown(Key.ALT);// 按下 Alt 键
action.keyUp(Keys.CONTROL);// 释放 Ctrl 键
action.keyUp(Keys.SHIFT);// 释放 Shift 键
action.keyUp(Keys.ALT);// 释放 Alt 键
修饰键是键盘上的一个或者一组特别的键,包括Shift、Ctrl、Alt(Option)、AltGr、Windows logo、Command、FN(Function)等,与一般按键同时使用的时候,用来临时改变一般键盘的普通行为。
我们发现, Actions 类和WebElement 类都有一个sendKeys(CharSequence key)方法,这两个方法对于一般的输入操作基本上相同,不同点在于以下几点:
Actions中的sendKeys(CharSequence key)对于修饰键 (Modifier Keys) 的调用并不会释放,也就是说当调用actions.sendKeys(Keys.ALT)、actions.sendKeys(Keys.CONTROL)、action.sendKeys(Keys.SHIFT)的时候,相当于调用 actions.keyDown(keysToSend),而如果在现实的应用中想要模拟按下并且释放这些修饰键,应该再调用action.sendKeys(keys.NULL)来完成这个动作。- 当
Actions的sendKeys(keysToSend)执行完之后,焦点就不在当前元素了。所以我们可以使用 sendKeys(Keys.TAB) 来切换元素的焦点,从而达到选择元素的作用,这个最常用到的场景就是在用户名和密码的输入过程中。
下面以一个百度搜索测试的例子来演示键盘操作:
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.interactions.Actions;public class ElementTest {public static void main(String[] args) {// 指定浏览器驱动的路径String driverPath = "E:/source/driver/chromedriver_80_2.exe";System.setProperty("webdriver.chrome.driver", driverPath);// 创建一个chrome driverWebDriver driver = new ChromeDriver();// 页面最大化driver.manage().window().maximize();try {// 访问测试页面driver.get("http://www.baidu.com");WebElement input = driver.findElement(By.id("kw"));input.sendKeys("测试试");// 按下退格键删除最后一个字input.sendKeys(Keys.BACK_SPACE);Thread.sleep(1000);Actions actions = new Actions(driver);// 按下回车键actions.sendKeys(Keys.ENTER).perform();Thread.sleep(15000);} catch (Exception e) {e.printStackTrace();} finally {driver.quit();}}
}
6 元素等待
在UI自动化执行过程中,如果页面或元素没有加载完成,就进行下一步操作,无疑是会抛出异常的,因此selenium提供了多种元素等待的方法。
6.1 隐式等待
隐式等待是一种全局设置,在driver的整个生命周期都有效,设置方式如下:
driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
按源码解释,驱动程序会轮询页面,直到找到该元素(找到后立即执行下一步)或超时(抛出org.openqa.selenium.NoSuchElementException)。这种设置应该谨慎,充分考虑Xpath等方式定位元素较慢的可能性。
6.2 显式等待
显示等待相对于隐式等待更加灵活,能针对各个元素进行单独的设置。只有满足显式等待的条件满足,测试代码才会继续向后执行后续的测试逻辑,如果超过设定的最大显式等待时间阈值, 这测试程序会抛出异常。
等待方法由ExpectedConditions类提供,常用的有以下几个(E代表ExpectedCondition):
E<Boolean> titleIs(final String title):判断标题是否是给定标题。E<Boolean> titleContains(final String title):判断标题是否包含给定标题。E<WebElement> presenceOfElementLocated(final By locator):判断页面元素在页面中存在。E<Boolean> textToBePresentInElement(final WebElement element, final String text):给定元素中是否包含特定的文本。E<WebElement> elementToBeClickable(final By locator):判断给定元素是否可点击。E<Boolean> elementToBeSelected(WebElement element):判断给定元素是否处于选中状态。
还有非常多的其他判断方法,可以根据场景灵活选用。下面以百度搜索为例,演示显示等待的使用:
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;public class ElementTest {public static void main(String[] args) {// 指定浏览器驱动的路径String driverPath = "E:/source/driver/chromedriver_80_2.exe";System.setProperty("webdriver.chrome.driver", driverPath);// 创建一个chrome driverWebDriver driver = new ChromeDriver();// 页面最大化driver.manage().window().maximize();try {// 设定显示等待时间为3sWebDriverWait wait = new WebDriverWait(driver, 3);// 访问测试页面driver.get("http://www.baidu.com");// 设置By.id("abc")这个元素加载完成才进行下一步,最多等待3s,否则抛出异常wait.until(ExpectedConditions.presenceOfElementLocated(By.id("abc")));driver.findElement(By.id("kw")).sendKeys("测试");Thread.sleep(5000);} catch (Exception e) {e.printStackTrace();} finally {driver.quit();}}
}

















