简介 什么是Selenium?
一套软件工具,用来支持不同的自动化测试框架
跨平台:linux、windows、mac,支持多种编程语言
核心功能就是可以在多个浏览器上进行自动化测试
目前已经被google , 百度, 腾讯等公司广泛使用
能够实现类似商业工具的大部分功能,并且还实现了商业工具不能支持的功能
Selenium的发展历史 2004年在ThoughtWorks 公司, 一个叫做Jason Huggins为了减少手工测试的工作, 自己写了一套Javascript的库, 这套库可以进行页面交互, 并且可以重复的在不同浏览器上进行重复的测试操作。这套库后来变为了Selenium Core. 为Selenium Remote Control (RC) 和Selenium IDE 提供了坚实的核心基础能力。Selenium 的作用是划时代的,因为他允许你使用多种语言来控制浏览器。 浏览器的对JS的安全限制也对Selenium的发展带来了困扰,并且Web程序也越来越大,特性也越来越多,都对selenium的发展来说带来了不少困难。2006年Google 的工程师Simon Stewart开启了一个叫做WebDriver的项目, 此项目可以直接让测试工具使用浏览器和操作系统本身提供的方法, 借此来绕过JS环境的沙盒效应, WebDriver项目目标就是为了解决Selenium的痛处。 2008年 Selenium 和 WebDriver 这两个项目进行了合并, Selenium 2.0 出现了,也就是大家说的WebDriver。
Selenium2的特点 Selenium 2,又名 WebDriver,它的主要新功能是集成了 Selenium 1.0 以及 WebDriver(WebDriver 曾经是 Selenium 的竞争对手)。也就是说 Selenium 2 是 Selenium 和 WebDriver 两个项目的合并,即 Selenium 2 兼容 Selenium,它既支持 Selenium API 也支持 WebDriver API。 WebDriver是一个用来进行复杂重复的web自动化测试的工具。意在提供一种比Selenium1.0更简单易学,有利于维护的API。它没有和任何测试框架进行绑定,所以他可以很好的在单元测试和main方法中调用。一旦创建好一个Selenium工程,你马上会发现WebDriver和其他类库一样:它是完全独立的,你可以直接使用而不需要考虑其他配置,这个Selenium RC是截然相反的。
Selenium2相比Selenium1的优点 Selenium1.0不能处理以下事件:
本机键盘和鼠标事件
同源策略XSS/HTTP(S)
弹出框,对话框(基本身份认证,自签名的证书和文件上传/下载)
Webdriver的优点:
当这两个框架被合并后,一个框架的缺陷被另一个框架所弥补。WebDriver对浏览器的支持需要对应框架开发工程师做对应的开发;同样Selenium必须操作真实浏览器,但是WebDriver可以HTML unit Driver来模拟浏览器,在内存中执行用例,更加的轻便。Selenium1.0解决了自动化测试中的一些常见问题,WebDriver更好的解决了沙箱限制。WebDriver不支持并行,但是Selenium Grid解决了这个问题。
Selenium的使用(以java为例) 1) maven 依赖
1 2 3 4 5 <dependency > <groupId > org.seleniumhq.selenium</groupId > <artifactId > selenium-java</artifactId > <version > 3.14.0</version > </dependency >
2) 基本使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 public static void main (String[] args) { System.setProperty("webdriver.chrome.driver" , "lib/chromedriver" ); ChromeDriver driver = new ChromeDriver(); driver.get("http://www.baidu.com" ); WebElement loginLink = driver.findElement(By.partialLinkText("登" )); loginLink.click(); WebElement button = driver.findElement(By.xpath("/html/body/div/input[@value='查询']" )); button.isEnabled(); button.click(); WebElement textinput = driver.findElement(By.id("usernameid" )); textinput.sendKeys("这是输入的关键字" ); textinput.clear(); textinput.getAttribute("value" ); Select select = new Select(driver.findElement(By.id("proAddItem_kind" ))); select.selectByIndex(2 ); select.selectByValue("18" ); select.selectByVisibleText("种类AA" ); List<WebElement> options = select.getOptions(); for (WebElement webElement : options) { System.out.println(webElement.getText()); } WebElement apple = driver.findElement(By.xpath("//input[@type='radio'][@value='Apple']" )); apple.click(); apple.isSelected(); apple.getAttribute("value" ); driver.close(); }
元素的定位 1) 常见的定位方法
1 2 3 4 5 6 7 8 9 10 11 定位方法 Java语言实现实例 --------------------------------------------------------------------------- id 定位 driver.findElement(By.id(“id的值”)); name定位 driver.findElement(By.name(“name的值”)); 链接的全部文字定位 driver.findElement(By.linkText(“链接的全部文字”)); 链接的部分文字定位 driver.findElement(By.partialLinkText(“链接的部分文字”)); css 方式定位 driver.findElement(By.cssSelector(“css表达式”)); xpath 方式定位 driver.findElement(By.xpath(“xpath表达式”)); Class 名称定位 driver.findElement(By.className(“class属性”)); TagName 标签名称定位 driver.findElement(By.tagName(“标签名称”)); Jquery方式 ((JavascriptExecutor) driver).executeScript(“return jQuery.find(“jquery表达式”)”)
在使用selenium webdriver进行元素定位时,通常使用findElement或findElements方法结合By类返回元素句柄来定位元素 findElement() 方法返回一个元素, 如果没有找到,会抛出一个异常 NoElementFindException() findElements()方法返回多个元素, 如果没有找到,会返回空数组, 不会抛出异常
2) 选择定位方法的策略
策略是, 选择简单,稳定的定位方法。
当页面元素有id属性的时候,尽量使用id来定位。没有的话,再选择其他定位方法
cssSelector 执行速度快,推荐使用
定位超链接的时候,可以考虑linkText或partialLinkText:是要注意的是 ,文本经常发生改变,所以不推荐用
xpath 功能最强悍。当时执行速度慢,因为需要查找整个DOM,所以尽量少用。实在没有办法的时候,才使用xpath
操作浏览器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public static void main (String[] args) throws Exception { System.setProperty("webdriver.chrome.driver" , "lib/chromedriver" ); ChromeDriver driver = new ChromeDriver(); driver.get("http://www.baidu.com" ); Thread.sleep(3000 ); driver.manage().window().maximize(); driver.navigate().refresh(); driver.navigate().back(); driver.navigate().forward(); Actions actions = new Actions(driver); actions.contextClick(driver.findElement(By.id("kw" ))).perform(); WindowsUtils.tryToKillByName("chrome" ); driver.close(); }
操作对话框 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public static void main (String[] args) throws Exception { System.setProperty("webdriver.chrome.driver" , "lib/chromedriver" ); ChromeDriver driver = new ChromeDriver(); driver.get("http://www.baidu.com" ); WebElement alertButton = driver.findElement(By.xpath("//input[@value='alert']" )); alertButton.click(); Alert javascriptAlert = driver.switchTo().alert(); System.out.println(javascriptAlert.getText()); javascriptAlert.accept(); driver.close(); }
智能等待页面加载完成 我们经常会碰到用selenium操作页面上某个元素的时候,需要等待页面加载完成后,才能操作。 否则页面上的元素不存在,会抛出异常。或者碰到AJAX异步加载,我们需要等待元素加载完成后,才能操作。selenium中提供了非常简单,智能的方法,来判断元素是否存在。
1 2 3 4 5 6 7 8 9 10 11 12 public static void main (String[] args) throws Exception { System.setProperty("webdriver.chrome.driver" , "lib/chromedriver" ); ChromeDriver driver = new ChromeDriver(); driver.get("file:////Users/zhangqingli/Desktop/aaa.html" ); driver.manage().timeouts().implicitlyWait(10 , TimeUnit.SECONDS); WebElement element = driver.findElement(By.cssSelector(".red_box" )); ((JavascriptExecutor)driver).executeScript("arguments[0].style.border = \"5px solid yellow\"" ,element); driver.close(); }
显示等待:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 titleIs(String) 标题是不是“xxxx” titleContains(String) 标题是不是包含“XXX” presenceOfElementLocated(By) 判断该元素是否被加载在DOM中,并不代表该元素一定可见 visibilityOfElementLocated(By) 判断元素是否可见(非隐藏,并且元素的宽和高都不等以0) visibilityOf(WebElement) 判断元素(定位后)是否可见 presenceOfAllElementsLocatedBy(By) 只要存在一个就是true textToBePresentInElementLocated(By, String) 元素中的text是否包含预期的字符串 textToBePresentInElementValue(By, String) 元素的value属性中是否包含预期的字符串 frameToBeAvailableAndSwitchToIt(By) 判断该表单是否可以切过去,可以就切过去并返回true,否则返回false invisibilityOfElementLocated(By) 判断某个元素是否不存在于DOM树或不可见 elementToBeClickable(By) 判断元素是否可见并且是可以点击的 stalenessOf(WebElement) 等到一个元素从DOM树中移除 elementToBeSelected(WebElement) 判断某个元素是否被选中,一般用在下拉列表 elementSelectionStateToBe(By, boolean) 判断某个元素的选中状态是否符合预期 elementSelectionStateToBe(WebElement, boolean) 与上一个方法一样,只是该方法参数为定位后的元素, 上一个方法接收的参数为定位,判断某个元素(已定位)的选中状态是否符合预期 alertIsPresent() 判断页面中是否存在alert textToBePresentInElement(By locator) 在页面元素中是否包含特定的文本
如果超过设定的最大显式等待时间阈值,则测试程序会抛出异常。
隐式等待:
1 driver.manage().timeouts().implicitlyWait(10 , TimeUnit.SECONDS);
隐式等待是通过一定的时长等待页面上某个元素加载完成。如果超过了设置的时长元素还没有被加载出来,则抛出NoSuchElementException异常。 代码中设置等待时间为10秒。首先这个10秒并非是一个固定的等待时间,它并不会影响脚本的执行速度。其次,它并不针对页面上的某一元素进行等待。当脚本执行到某个元素定位时,如果元素可以定位,则继续执行;如果元素定位不到,则它将会以轮询的方式不断地判断元素是否被定位到。假设,第5秒等位到元素,就继续执行;但是如果超出设置的这个10秒,那就直接抛出异常。
处理Iframe中的元素 有时候我们定位元素的时候,发现怎么都定位不了。 这时候你需要查一查你要定位的元素是否在iframe里面
1 2 3 4 5 6 7 8 9 driver.findElement(By.id("maininput" )).sendKeys("main input" ); driver.switchTo().frame("frameA" ); driver.findElement(By.id("iframeinput" )).sendKeys("iframe input" ); driver.switchTo().defaultContent(); driver.findElement(By.id("maininput" )).sendKeys("main input" );
示例实战 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 package bigdata.resource_manage;import java.io.BufferedReader;import java.io.File;import java.io.FileInputStream;import java.io.InputStreamReader;import java.util.List;import org.openqa.selenium.By;import org.openqa.selenium.WebElement;import org.openqa.selenium.chrome.ChromeDriver;import org.openqa.selenium.support.ui.ExpectedConditions;import org.openqa.selenium.support.ui.Select;import org.openqa.selenium.support.ui.WebDriverWait;import bigdata.commons.BigdataHelper;import commons.ChromeDriverHelper;public class ResourceManageOperationFlow { private static final String CONFIG_FILE_NAME = "mdata/bigdata/prod_fq_uc_datasource_table.list" ; private static final String DATABASE_VISIBLE_TEXT = "分期用户中心" ; private static final String BUZ_TYPE_VISIBLE_TEXT = "FQ" ; public static void main (String[] args) throws Exception { BigdataHelper.login(); BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(new File(CONFIG_FILE_NAME)))); String line = "" ; while ((line=br.readLine()) != null ) { String[] splits = line.split("\t" ); if (splits.length != 3 ) { continue ; } String tableName = splits[0 ]; String checkColumn = splits[1 ]; String splitBy = splits[2 ]; addAndSyncMysqlTableOnBigdataPlatform(DATABASE_VISIBLE_TEXT, BUZ_TYPE_VISIBLE_TEXT, tableName, checkColumn, splitBy); } br.close(); } public static void addAndSyncMysqlTableOnBigdataPlatform (String databaseVisibleText, String buzTypeVisibleText, String tableName, String checkColumn, String splitBy) throws Exception { Thread.sleep(2000 ); ChromeDriver driver = ChromeDriverHelper.getDriver(); WebElement pzglEle = driver.findElement(By.xpath("//*[@id=\"rrapp\"]/aside/section/ul/li[7]/a" )); pzglEle.click(); WebElement sjybEle = new WebDriverWait(driver,20 ).until(ExpectedConditions.elementToBeClickable(By.xpath("//*[@id=\"rrapp\"]/aside/section/ul/li[7]/ul/li[3]/a" ))); sjybEle.click(); driver.switchTo().frame(0 ); WebElement xzEle = new WebDriverWait(driver, 20 ).until(ExpectedConditions.elementToBeClickable(By.xpath("//*[@id=\"rrapp\"]/div[1]/div[1]/a[2]" ))); xzEle.click(); driver.switchTo().defaultContent(); driver.switchTo().frame(0 ); By datasourceSelectBy = By.xpath("//*[@id=\"rrapp\"]/div[2]/form/div[1]/div[2]/select" ); Select datasourceSelect = new Select(driver.findElement(datasourceSelectBy)); datasourceSelect.selectByVisibleText(databaseVisibleText); Thread.sleep(3000 ); By ywlxBy = By.xpath("//*[@id=\"rrapp\"]/div[2]/form/div[2]/div[2]/select" ); Select ywlxSelect = new Select(driver.findElement(ywlxBy)); ywlxSelect.selectByVisibleText(buzTypeVisibleText); Thread.sleep(2000 ); new WebDriverWait(driver, 20 ).until(ExpectedConditions.presenceOfElementLocated(By.xpath("//*[@id=\"rrapp\"]/div[2]/form/div[3]/div[2]/select/option[1]" ))); Select tablenameSelect = new Select(driver.findElement(By.xpath("//*[@id=\"rrapp\"]/div[2]/form/div[3]/div[2]/select" ))); tablenameSelect.selectByValue(tableName); Thread.sleep(1000 ); if (!"-" .equals(checkColumn)) { new WebDriverWait(driver, 20 ).until(ExpectedConditions.presenceOfElementLocated(By.xpath("//*[@id=\"rrapp\"]/div[2]/form/div[4]/div[2]/select/option[@value='" + checkColumn +"']" ))); Select zlzdSelect = new Select(driver.findElement(By.xpath("//*[@id=\"rrapp\"]/div[2]/form/div[4]/div[2]/select" ))); zlzdSelect.selectByValue(checkColumn); Thread.sleep(1000 ); } if (!"-" .equals(splitBy)) { new WebDriverWait(driver, 20 ).until(ExpectedConditions.presenceOfElementLocated(By.xpath("//*[@id=\"rrapp\"]/div[2]/form/div[5]/div[2]/select/option[@value='" + splitBy +"']" ))); Select splitBySelect = new Select(driver.findElement(By.xpath("//*[@id=\"rrapp\"]/div[2]/form/div[5]/div[2]/select" ))); splitBySelect.selectByValue(splitBy); Thread.sleep(1000 ); } By ckzdButtonBy = By.xpath("//*[@id=\"rrapp\"]/div[2]/form/div[6]/input[3]" ); WebElement ckzdButton = new WebDriverWait(driver, 3 ).until(ExpectedConditions.presenceOfElementLocated(ckzdButtonBy)); ckzdButton.click(); Thread.sleep(3000 ); WebElement checkboxes = new WebDriverWait(driver, 20 ).until(ExpectedConditions.presenceOfElementLocated(By.xpath("//*[@id=\"cb_columnsGrid\"]" ))); checkboxes.click(); WebElement submitButton = new WebDriverWait(driver, 20 ).until(ExpectedConditions.elementToBeClickable(By.xpath("//*[@id=\"rrapp\"]/div[2]/form/div[6]/input[1]" ))); submitButton.click(); Thread.sleep(1000 ); driver.switchTo().defaultContent(); WebElement confirmBoxButton = new WebDriverWait(driver, 20 ).until(ExpectedConditions.presenceOfElementLocated(By.xpath("//*[@type='dialog']/div[3]/a" ))); confirmBoxButton.click(); Thread.sleep(3000 ); driver.switchTo().frame(0 ); Thread.sleep(1000 ); WebElement tbodyEle = new WebDriverWait(driver, 20 ).until(ExpectedConditions.presenceOfElementLocated(By.xpath("//tbody" ))); List<WebElement> trEles = tbodyEle.findElements(By.xpath("tr[@role='row']" )); WebElement targetTr = null ; for (WebElement trEle : trEles) { WebElement tableNameTd = trEle.findElement(By.xpath("td[5]" )); String currentTableName = tableNameTd.getText(); currentTableName = currentTableName==null ? "" : currentTableName.trim(); if (currentTableName.equals(tableName)) { targetTr = trEle; break ; } } WebElement targetCheckbox = targetTr.findElement(By.xpath("td[2]/input[@type='checkbox']" )); targetCheckbox.click(); Thread.sleep(1000 ); WebElement yjtbButton = driver.findElement(By.xpath("//*[@id=\"rrapp\"]/div[1]/div[1]/a[5]" )); yjtbButton.click(); Thread.sleep(1000 ); driver.switchTo().defaultContent(); WebElement yjtbConfirmButton1 = driver.findElement(By.xpath("//*[@type='dialog']/div[3]/a[1]" )); yjtbConfirmButton1.click(); Thread.sleep(1000 ); WebElement yjtbConfirmButton2 = driver.findElement(By.xpath("//*[@type='dialog']/div[3]/a" )); yjtbConfirmButton2.click(); Thread.sleep(1000 ); } }