最近要做一个自动化数据填充的项目,领导说要用Selenium和Sikulix
给的要求是要用jar包,通过Java编写
但是翻遍论坛、官网,都是用Python或者其可视化界面的说明,而且这都少之又少
于是想自己写个总结的,也方便之后项目开发查阅
注:这篇文章只是介绍主要方法(我用到的),具体还有很多其他的,自行查阅吧^ - ^
自动化测试工具
selenium主要用于B/S架构,即浏览器
sikulix主要用于C/S架构,即客户端
通俗讲,涉及到网页,就可以用Selenium;若不是网页,就可以使用Sikulix
因为要操作浏览器,除了要下载Selenium的jar包外,还要下载浏览器驱动:
下载的驱动版本要一致
Selenium:
1、selenium-java-2.48.0.jar
2、selenium-server-standalone-2.48.0.jar
<<<我是下载地址>>>
浏览器驱动:
<<>>
<<>>
<<>>
<<>>
配置浏览器代码如下:
//设置浏览器驱动路径
System.setProperty("webdriver.ie.driver","C:\\IEDriverServer.exe")
//一般是启动对应驱动的默认浏览器,也可以手动指定浏览器的安装路径
System.setProperty("webdriver.firefox.bin", "E:/firefox.exe");
代码 | 功能 |
---|---|
WebDriver driver = new InternetExplorerDriver() | 创建IE浏览器驱动 对应的,还有其他浏览器驱动: * FirefoxDriver 火狐 * ChromeDriver 谷歌 即new的对象替换成对应的浏览器名字即可 |
driver.get(“www.baidu.com”) | 打开指定网址 |
driver.manage().window().maximize() | 最大化窗口 |
driver.quit() | 关闭浏览器 |
示例代码如下:
//启动IE浏览器
//1.设置浏览器驱动路径
System.setProperty("webdriver.ie.driver","C:\\IEDriverServer.exe")
//2.创建驱动
WebDriver driver = new InternetExplorerDriver();
//3.打开百度
driver.get("http://localhost:8080/heima");
//4.最大化窗口
driver.manage().window().maximize();
//5.关闭浏览器
driver.quit();
代码 | 功能 |
---|---|
driver.findElement(By.id(“元素id”)) | 根据id获取元素 |
driver.findElement(By.partialLinkText(“文本”)) | 根据超链接的文本进行模糊获取 linkText()是全匹配 |
driver.findElement(By.tagName(“元素标签”)) | 根据标签获取元素,例如所有的input标签 |
driver.findElement(By.xpath(“路径”)) | 根据xpath定位元素 |
一般除了id获取,其他方式获取都会获取到多个元素,此时应该用driver.findElements()方法
获取的元素类型为:List< WebElement>
示例代码如下:
//1、根据id获取元素
WebElement input = driver.findElement(By.id("kw"));
//2、根据超链接文本的部分内容获取元素
WebElement aHref = driver.findElement(By.partialLinkText("百度百科"));
//3、根据tag_name + xPath获取元素
driver.findElements(By.xpath("//*[@id=\"app\"]/select[1]"));
应用场景:
1、WebElement元素有click方法,用来触发单击事件,但是IE浏览器对该方法不支持,所以需要用到JS
2、WebElement元素有sendKeys方法,用来输入信息,但是实际会输入很慢,可以直接用JS改变value属性
代码 | 功能 |
---|---|
driver.executeScript(js字符串, 元素) | 执行js代码 |
示例代码如下:
//-------------点击-------------
//创建IE驱动
WebDriver driver = new InternetExplorerDriver();
//定义点击js
String js = "arguments[0].click()";
//获取元素
WebElement input = driver.findElement(By.id("kw"));
//执行
((InternetExplorerDriver) driver).executeScript(js, input);
//-------------输入信息-------------
String js = "document.getElementById('kw').value='Eugenema'";
((InternetExplorerDriver) driver).executeScript(js);
代码 | 功能 |
---|---|
element.sendKeys(Keys.ENTER) | 向element元素中输入回车 |
driver.getMouse().mouseMove(element.getCoordinates()) | 鼠标悬停 driver的类型不能是WebDriver element的类型是RemoteWebElement |
代码 | 功能 |
---|---|
Keys.ENTER | 回车 |
Keys.CONTROL, ‘a’ | Ctrl + A |
Keys.UP | 上方向键 |
示例代码如下:
//-------------获取超链接元素,鼠标悬停其上-------------
RemoteWebElement aHref = (RemoteWebElement) driver.findElement(By.partialLinkText("A班"));
((InternetExplorerDriver) driver).getMouse().mouseMove(aHref.getCoordinates());
//-------------获取输入文本框,向文本框输入回车-------------
WebElement input = driver.findElement(By.id("kw"));
input.sendKeys(Keys.ENTER);
通过xPath获取所有复选框,全选
示例代码如下:
List<WebElement> input = driver.findElements(By.xpath("//input[@type='checkbox']"));
String js = "arguments[0].click()";
for (WebElement webElement : input) {
if(webElement.getAttribute("checked") == null){
//表示未选中
((InternetExplorerDriver) driver).executeScript(js, webElement);
}
}
通过标签获取所有下拉列表,选中特定选项
示例代码如下:
List<WebElement> selects = driver.findElements(By.tagName("select"));
//将第一个下拉列表创建成对象
Select select = new Select(selects.get(0));
//获取所有选项
List<WebElement> options = select.getOptions();
//找到“湖南省”选项并选中
for (WebElement option : options) {
if(option.getText().equals("湖南省")){
option.click();
}
}
//将第二个下拉列表创建成对象
select = new Select(selects.get(1));
//获取所有选项
options = select.getOptions();
//找到“湘潭市”选项并选中
for (WebElement option : options) {
if(option.getText().equals("湘潭市")){
option.click();
}
}
通过xpath获取所有单选按钮,将第一个未选中的选中
示例代码如下:
List<WebElement> audios = driver.findElements(By.xpath("//input[@type='radio']"));
js = "arguments[0].click()";
for (WebElement audio : audios) {
if(!audio.isSelected()){
((InternetExplorerDriver) driver).executeScript(js, audio);
}
}
将鼠标移到某父级菜单上,显示下一级菜单
示例代码如下:
RemoteWebElement aHref = (RemoteWebElement) driver.findElement(By.partialLinkText("A班"));
((InternetExplorerDriver) driver).getMouse().mouseMove(aHref.getCoordinates());
鼠标点击父级菜单指定位置,调出下一级菜单
示例代码如下:
WebElement element = driver.findElement(By.xpath("//*[@id=\"menu\"]/ul/li[2]/span"));
clickJs(element);
clickJs(driver.findElement(By.partialLinkText("菜单 2-1")));
public static void clickJs(WebElement element){
String js = "arguments[0].click()";
((InternetExplorerDriver) driver).executeScript(js, element);
}
一般有alert弹窗、confirm弹窗以及能够输入信息的prompt弹窗
示例代码如下:
//1、处理alert弹窗
driver.switchTo().alert().accept();
//2、处理confirm弹窗
driver.switchTo().alert().dismiss(); //点击取消
driver.switchTo().alert().accept(); //点击确认
//3、处理prompt弹窗
System.out.println(driver.switchTo().alert().getText());//获取弹窗提示文本
driver.switchTo().alert().sendKeys("Eugenema输入信息"); //向窗口输入文本
driver.switchTo().alert().accept(); //点击确认
当页面通过超链接等途径跳转到新页面时,想要获取新页面上的元素,就需要切换
Selenium通过页面标志来定位页面,所以要切换页面就需要知道新页面的标志
代码 | 功能 |
---|---|
driver.getWindowHandle() | 获取当前页面的标志 |
driver.getWindowHandles() | 获取所有页面的标志 |
driver.switchTo().window(“页面标志”) | 切换到指定页面 |
示例代码:
//获取当前窗口
String current_handle = driver.getWindowHandle();
//获取所有窗口
Set<String> windowHandles = driver.getWindowHandles();
//遍历窗口,找到新窗口就跳转
Iterator<String> it = windowHandles.iterator();
while(it.hasNext()){
//若是当前窗口,就跳过
String next = it.next();
if(next == current_handle){
continue;
}
//跳入新窗口
WebDriver new_driver = driver.switchTo().window(next);
}
//切换回旧窗口
driver.switchTo().window(current_handle);
如果切换页面后找不到元素了,但是新页面有该元素,可以通过下面获取页面源码driver.getPageSource(),查看当前driver是在哪个页面上,再决定是否切换页面
代码 | 功能 |
---|---|
driver.getPageSource() | 获取页面的源码 |
element.getAttribute(“innerHTML”) | 获取该元素的源码 |
首先,找不到元素有多种情况,除了上面页面跳转,还有以下情况:
现在就来聊一下如何去解决~
这个问题一般出现在网页打开速度较慢的情况,此时可能元素还未加载出来,自然就无法定位了
那么解决办法就是:等!
全局隐式等待
这也是官方给出的解决办法,推荐使用
m_oDriver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
参数为:时间,时间单位
上述语句的作用是等待5秒,隐式全局等待
隐式等待:全局化设置,在规定时间内寻找元素。寻找到则继续执行;寻找不到则继续寻找。直到规定时间未找到,抛出异常
显式等待:对每一次寻找做等待限制。显式等待可自定义找到和未找到动作,非全局(这里不做讲解)
下面模拟找不到元素的情况:
/**指定IE驱动路径*/
private static String g_oDriverPath = System.getProperty("user.dir") + File.separator
+ "webDriver" + File.separator + "IEDriverServer.exe";
public static void main(String[] args) throws Exception {
//设置IE驱动
System.setProperty("webdriver.ie.driver", g_oDriverPath);
//打开IE窗口
WebDriver m_oDriver = new InternetExplorerDriver();
//全局设置等待时间
m_oDriver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
//查找元素
m_oDriver.findElement(By.id("nihai"));
}
//未开启全局等待
javaException in thread "main" org.openqa.selenium.NoSuchElementException: Unable to find element with id == nihai (WARNING: The server did not provide any stacktrace information)
Command duration or timeout: 288 milliseconds
//开启全局等待
Exception in thread "main" org.openqa.selenium.NoSuchElementException: Unable to find element with id == nihai (WARNING: The server did not provide any stacktrace information)
Command duration or timeout: 5.12 seconds
可以看到,出错时间有了明显延迟,一个288毫秒,一个5.12秒
不过,在实际项目中可能出现失灵的情况,即全局设置失效!!!
于是就需要手动线程睡眠去解决
不过有个缺点:官方提供的方法,在找到元素后就会停止等待,而如果手动线程睡眠,则必须等待线程唤醒才能去找到元素,不管元素是否已经加载完
所以,建议根据项目实际情况、要求去选择合适的方法
一般出现在循环读取数据时,数据编辑页面和显示页面不同导致
//打开IE窗口
WebDriver m_oDriver = new InternetExplorerDriver();
//进入网页
m_oDriver.get("www.eugenema.com");
// 获取所有行数据,list中每一个webElement就是一行数据
List<WebElement> elements = m_oDriver .findElements(By.xpath("//*[@id=\"form:cdmData:tbody_element\"]/tr"));
//遍历所有行数据,编辑
for( int i=0; i<elements.size(); i++){
//点击编辑按钮
//进入新的页面开始编辑
//编辑完,点击完成,自动返回之前学生列表页面
}
在编辑完第一条数据后,从新页面返回去编辑第二条数据时,会报错
这是因为获取所有元素的语句在for循环外面,而selenium认定切换了页面就需要重新获取所有元素,不然之前list里存的都是过期的元素
即将获取所有行元素的语句复制一份在for循环(因为for循环需要知道循环次数,必须在for循环外先获取一次)
这种情况出现在一些比较老的项目中(很不幸,我就是在老项目中接触的这项技术 TAT)
也就是 < iframe > 标签,用于在一个页面中嵌套另一个页面
此时如果想获取iframe嵌套页面内的元素,直接定位是不行的,虽然F12能看到元素的id,但是你就是获取不到
需要先切换面板到嵌套页面,再获取
//id是iframe的id
driver.switchTo().frame(driver.findElement(By.id("stframem")));
<<<点击下载Sikulix>>>
主要操作对象为Screen
通过识别图片,检测屏幕上与图片相似度最高的区域,获取到坐标
代码 | 功能 |
---|---|
screen.wait(“图片路径” , 时间) | 等待某个图片出现,超过指定时间报异常 时间可不写 |
screen.waitVanish(“图片路径” , 时间) | 只有指定图片消失后,才向下执行 时间可不写 |
screen.find(“图片路径”) | 查找相似度最高的图片 返回match对象 可以通过该对象进行点击、获取坐标 |
screen.findAll(“图片路径”) | 查找所有相似度的图片,返回match列表 |
示例代码:
//图片存放路径:根目录下的image
private static String g_sImagePath = System.getProperty("user.dir") +
File.separator + "image" + File.separator;
//创建Screen对象
Screen screen = new Screen();
//等待图标出现
screen.wait(g_sImagePath + "图片.png", 100);
//获取某个图片在屏幕上的位置
Match match = screen.find(g_sImagePath + "图片.png");
System.out.println(match.getX() + " " + match.getY() + " " + match.getH() + " " + match.getW());
代码 | 功能 |
---|---|
screen.doubleClick(“图片路径”) | 双击指定图片 click即单击 |
screen.hover(“图片路径”) | 将鼠标移动到该处 |
screen.mouseMove(x , y) | 鼠标在原有基础上移动 例如(-50,0),就是左移50 |
screen.mouseDown(Button.LEFT) | 点击鼠标左键 |
screen.mouseUp() | 鼠标松开 |
screen.dragDrop(match1 , match2) | 从match1点击不放鼠标,滑到match2 |
示例代码:
//单击
screen.click(g_sImagePath + "图片.png");
//双击
screen.doubleClick(g_sImagePath + "图片.png");
//移动到该处
screen.hover(g_sImagePath + "13.png");
//左移50
screen.mouseMove(-50,0);
//点击
screen.mouseDown(Button.LEFT);
screen.mouseUp();
//1、创建match对象
Match match1 = new Match();
match1.setX(933);
match1.setY(10);
Match match2 = new Match();
match2.setX(20);
match2.setY(900);
//2、两种方式:进行拖拽
match1.dragDrop(match2);
//screen.dragDrop(match1,match2);
代码 | 功能 |
---|---|
screen.type(Keys.CAPS_LOCK) | 按下大写锁定键参数还可以是字符串,代表输入该字符串 |
screen.type(“m”,Key.WIN) | 最小化所有窗口 |
示例代码:
//图片存放路径:根目录下的image
private static String g_sImagePath = System.getProperty("user.dir") +
File.separator + "image" + File.separator;
//创建Screen对象
Screen screen = new Screen();
//1、最小化所有窗口
screen.type("m", Key.WIN);
//2、等待输入框
screen.wait(g_sImagePath + "输入框.png", 100);
//3、点击输入框
screen.click(g_sImagePath + "输入框.png");
//4、输入文字
screen.type("D:\\Configpath");
//5、敲回车
screen.type(Keys.ENTER);