Java+Selenium
mvn仓库地址:https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java
相关视频:https://www.bilibili.com/video/BV11h411m7hK
第一个示例
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
public class TestSelenium {
public static void main(String[] args) {
// 请求过后不退出浏览器
ChromeOptions options = new ChromeOptions();
options.setExperimentalOption("detach", true);
ChromeDriver driver = new ChromeDriver(options);
driver.get("https://www.baidu.com");
}
}
注意
这里只是为了方便使用,常规来说,这里应该和TestNG组合使用
定位并操作元素
import org.openqa.selenium.By;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
public class TestSelenium {
public ChromeOptions options;
public ChromeDriver driver;
@BeforeClass
public void setUp(){
options = new ChromeOptions();
options.setExperimentalOption("detach", true);
}
@Test
public void openBrowser(){
driver = new ChromeDriver(options);
driver.get("https://www.baidu.com");
}
@Test
public void testClick(){
driver.findElement(By.id("kw")).sendKeys("HelloWorld");
driver.findElement(By.id("su")).click();
}
}
提示
搜索元素不仅可以通过 By.id()
这样的方式来做。除了 id
之外,还可以通过 name
和 class的name
来做
通过XPath和CSS定位元素
首先使用浏览器检查元素,按下组合键 Ctrl + F
进行搜索
空白处的提示写的是:按字符串、选择器或XPath 查找
或者 Find by string, selector or XPath
,下文的XPath表达式就在这里填写
XPath 匹配的是元素的属性,例如:img元素的src属性,a元素的href元素(id、class、name等也是元素的属性之一)
相关教程:https://www.runoob.com/xpath/xpath-tutorial.html
这里还是拿百度一下的页面进行举例://*[@id="kw"]
。这里定位到的也是该页面的输入框
//
:表示从任意位置开始匹配*
:表示匹配任意元素[]
:表示匹配元素的属性@
:表示访问元素的某个指定属性
如果精度不够,可以适当调整表达式。比如将 *
修改为 div
,这样就会只匹配 div元素了
如果精度还是不够,可以去匹配显示出来的文本值,示例://*[@id="su" and @value="百度一下"]
,这样匹配到的就是百度一下的按钮了。这里的 and
表示逻辑与的关系
有的按钮并不会以value属性的方式展示文字,遇到这种情况就使用该方式进行匹配文本://*[text()="文本值"]
用来通过XPath匹配元素的代码如下:
import org.openqa.selenium.By;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
public class TestSelenium {
public ChromeOptions options;
public ChromeDriver driver;
@BeforeClass
public void setUp(){
options = new ChromeOptions();
options.setExperimentalOption("detach", true);
}
@Test
public void openBrowser(){
driver = new ChromeDriver(options);
driver.get("https://www.baidu.com");
}
@Test
public void testClick(){
driver.findElement(By.xpath("//*[@id=\"kw\"]")).sendKeys("HelloWorld");
driver.findElement(By.xpath("//*[@id=\"su\" and @value=\"百度一下\"]")).click();
}
}
通过css定位
import org.openqa.selenium.By;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
public class TestSelenium {
public ChromeOptions options;
public ChromeDriver driver;
@BeforeClass
public void setUp(){
options = new ChromeOptions();
options.setExperimentalOption("detach", true);
}
@Test
public void openBrowser(){
driver = new ChromeDriver(options);
driver.get("https://www.baidu.com");
}
@Test
public void testClick(){
// 注意,下方多个sendKeys会添加多个重复内容
// 从高级元素 直到指向 目标元素,元素之间使用空格分割,多个元素时使用id或者class区分,#或者.后跟名字,只写span.s_ipt_wr input#kw也会生效
driver.findElement(By.cssSelector("html body div div div#head_wrapper div div form#form span.s_ipt_wr input#kw")).sendKeys("HelloWorld");
driver.findElement(By.cssSelector("span.s_ipt_wr input#kw")).sendKeys("HelloWorld");
// >的左边是父级元素,右边是子级元素
driver.findElement(By.cssSelector("span.bg.s_ipt_wr.new-pmd.quickdelete-wrap>input#kw")).sendKeys("HelloWorld");
driver.findElement(By.cssSelector("span.s_ipt_wr>input#kw")).sendKeys("HelloWorld");
driver.findElement(By.id("su")).click();
}
}
Actions模拟鼠标
模拟鼠标移动并点击
代码示例:
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.interactions.Actions;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
public class TestSelenium {
public ChromeOptions options;
public ChromeDriver driver;
@BeforeClass
public void setUp(){
options = new ChromeOptions();
options.setExperimentalOption("detach", true);
}
@Test
public void openBrowser(){
driver = new ChromeDriver(options);
driver.get("https://www.baidu.com");
}
@Test
public void testAction(){
Actions actions = new Actions(driver);
WebElement btn = driver.findElement(By.linkText("更多"));
actions.moveToElement(btn);
WebElement musicElement = driver.findElement(By.xpath("//a[@name='tj_mp3']"));
actions.moveToElement(musicElement).click().perform();
}
}
模拟地图操作
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.interactions.Actions;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
public class TestSelenium {
public ChromeOptions options;
public ChromeDriver driver;
@BeforeClass
public void setUp(){
options = new ChromeOptions();
options.setExperimentalOption("detach", true);
}
@Test
public void openBrowser(){
driver = new ChromeDriver(options);
driver.get("https://map.baidu.com");
}
/**
* 注意:测试启动时,如果浏览器以小窗口打开,需要将鼠标的焦点置于浏览器页面中
*/
@Test
public void testAction(){
// 使用检查,发现百度地图的元素是一个id为mask的遮罩层
WebElement element = driver.findElement(By.id("mask"));
Actions actions = new Actions(driver);
// contextClick() 是右键点击
actions.moveToElement(element).contextClick();
// pause() 是暂停,参数是时间,单位是毫秒
actions.pause(3000);
// 点击 以此为起点
WebElement start = driver.findElement(By.id("cmitem_start"));
// 鼠标移动到该位置并点击
actions.moveToElement(start).click();
// 注意要写perform()方法,不写不会生效
actions.perform();
// 按下鼠标左键不松开
actions.clickAndHold();
// moveByOffset 是相对于鼠标或原点进行偏移,两个参数分别为X轴和Y轴,偏移单位是像素
actions.moveByOffset(200, 100);
// 松开鼠标
actions.release();
// 再次右键进行操作
actions.contextClick().pause(3000);
// 点击 以此为终点
WebElement end = driver.findElement(By.id("cmitem_end"));
actions.moveToElement(end).click().perform();
actions.perform();
}
}
浏览器切换窗口
import org.openqa.selenium.By;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import java.util.Set;
public class TestSelenium {
public ChromeOptions options;
public ChromeDriver driver;
@BeforeClass
public void setUp(){
options = new ChromeOptions();
options.setExperimentalOption("detach", true);
}
@Test
public void openBrowser(){
driver = new ChromeDriver(options);
driver.get("https://www.baidu.com");
}
@Test
public void testSwitch(){
// 通过文字找到元素,点击按钮,会打开一个新的窗口
driver.findElement(By.linkText("新闻")).click();
// 获取当前的窗口,这里指的是www.baidu.com
String current = driver.getWindowHandle();
// 获取所有的窗口
Set<String> windowHandles = driver.getWindowHandles();
// 单纯用来测试,不是实际业务代码。下面的w指的是新打开的窗口
for (String w: windowHandles){
if (!w.equals(current)){
driver.switchTo().window(w);
break;
}
}
// 切换窗口
driver.switchTo().window(current);
}
}
iframe切换窗口
这里用到的是安居客网站登录的页面:https://login.anjuke.com/login/form
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
public class TestSelenium {
public ChromeOptions options;
public ChromeDriver driver;
@BeforeClass
public void setUp(){
options = new ChromeOptions();
options.setExperimentalOption("detach", true);
}
@Test
public void openBrowser(){
driver = new ChromeDriver(options);
driver.get("https://login.anjuke.com/login/form");
}
/**
* 想要对iframe里面的元素进行操作,例如点击按钮,填写信息等。需要先switch到iframe里面才可以
*/
@Test
public void testSwitch(){
// 获取整个iframe元素
WebElement element = driver.findElement(By.id("iframeLoginIfm"));
// 切换到frame
driver.switchTo().frame(element);
// 点击账号密码登录
driver.findElement(By.linkText("账号密码登录")).click();
// 填写用户名
driver.findElement(By.id("pwdUserNameIpt")).sendKeys("mahe666");
}
}
等待
提示
适用场景举例:页面没有加载完全时操作元素,可能会导致报错。这时就需要等待一下
隐式等待
模拟场景,隐式等待时间是10秒
如果元素加载,在隐式等待时间之内完成,就会在元素加载完成后进行常规操作。如果等待3秒完成元素加载了,就会在3秒后开始查找元素
如果元素加载,在隐式等待期间一直未完成,不会继续等待,直接进行操作。因为未加载完的原因,可能会导致报错
// 隐式等待十秒
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
警告
下面这种方法也可以使用,但是在未来的新版本中不再支持了
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
注意
隐式等待的设置是全局的,不需要在每次需要等待的时候都设置一次
相关方法简要说明
// waitForElementPresent locator 等待直到某个元素在页面中存在
// waitForElementNotPresent locator 等待直到某个元素在页面中不存在
//
// waitForTextPresent text 等待直到某个文本在页面中存在
// waitForTextNotPresent text 等待直到某个文本在页面中不存在
//
// waitForText locator text 等待直到locator指定元素内的文本符合text
// waitForNotText locator text 等待直到locator指定元素内的文本不符合text
//
// waitForVisible locator 等待直到locator指定元素在页面中可见
// waitForNotVisible locator 等待直到locator指定元素在页面中不可见
//
// waitForTitle title 等待直到页面标题符合所指定的title
// waitForNotTitle title 等待直到页面标题不符合所指定的title
// waitForLocation url 等待直到页面的地址符合所指定的url
// waitForNotLocation url 等待直到页面的地址不符合所指定的url
//
// waitForValue locator value 等待直到locator指定的元素的value值符合指定的值
// waitForNotValue locator value 等待直到locator指定的元素的value值不符合指定的值
//
// waitForAttribute locator@attr value 等待直到locator指定的元素的attr属性值符合指定的值
// waitForNotAttribute locator@attr value 等待直到locator指定的元素的attr属性值不符合指定的值
//
// waitForChecked locator 等待直到locator指定的radio或checkbox成为选中状态
// waitForNotChecked locator 等待直到locator指定的radio或checkbox成为非选中状态
//
// waitForEditable locator 等待直到locator指定的input或textarea元素可编辑
// waitForNotEditable locator 等待直到locator指定的input或textarea元素不可编辑
// waitForXpathCount xpath count 等待直到页面符合xpath的数量为count
// waitForNotXpathCount xpath count 等待直到页面符合xpath的数量不为count
//
// waitForEval script pattern 等待直到script的执行结果符合pattern
// waitForNotEval script pattern 等待直到script的执行结果不符合pattern
显式等待
隐式等待有一个问题,就是如果实在找不到元素,就会等待10秒。例如:在旧版本的测试用例很多时,前端页面被开发人员改动了,可能就会出现这样的问题
这样的等待是没有结果的,就会让测试用例的效率减小
显示等待是针对某一个元素设置等待时间,不再是全局等待时间了
例如某个对话框,我明确知道它的显示时间会比较长,我就单独的为它添加等待时间
// 初始化对象
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
// 10秒,等待元素加载出来,加载不出来就会报错。返回的对象就是等待加载完成的元素
WebElement element = wait.until(ExpectedConditions.presenceOfElementLocated(By.id("")));