有关Selenium的介绍在网上实在是太多了,总结起来就是一个目前在web自动化方面运用最为广泛的一个开源自动化测试框架
path
:环境变量,老生常谈的问题了maven
,目前建议使用稳定版本的3.141.59:<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.141.59</version>
</dependency>
我这里主要用的是Chrome浏览器,所以就以Chrome为例
1)先去到selenium官网的下载中心https://www.seleniumhq.org/download/;往下翻,翻到如下图的位置:
2)进去后找到与你当前Chrome浏览器版本对应的driver版本,下载对应系统的driver(需要梯子,如果没有继续往下看)
如果你没有梯子,无法去官网下载driver的话,这里提供一个淘宝的镜像,在国内的网络就可以直接下载
https://npm.taobao.org/mirrors/chromedriver
3)下载完成后解压到自己指定的路径即可,别忘了将路径添加到环境变量中(这里以Mac为例)
$ echo 'export PATH=$PATH:/Users/qinzhen/Documents/TestDev/WebAuto/webdrivers/chromedrivers/chrome_77/' >> ~/.bash_profile
$ tail -1 ~/.bash_profile
export PATH=$PATH:/Users/qinzhen/Documents/TestDev/WebAuto/webdrivers/chromedrivers/chrome_77/
元素定位是做UI自动化最基础也是最重要的部分之一了,算是web自动化的大门,推开这扇门走进web自动化的世界
Selenium
的WebDriver
一共提供了九种定位方法,其中最常用的是前八种,先来看看在Java中的对应关系
定位方法 | 对应API | 说明 |
---|---|---|
id | By.id | 通过id号 |
class name | By.className | 通过class属性值 |
tag name | By.tagName | 通过tag属性值 |
name | By.name | 通过name属性值 |
link text | By.linkText | 通过链接的文本信息 |
partial link text | By.partialLinkText | 通过部分匹配的链接文本信息 |
css | By.cssSelector | 通过CSS |
xpath | By.xpath | 通过xpath |
javascript | ((JavascriptExecutor)driver).executeScript | 通过执行JavaScript定位元素,返回WebElement对象 |
如上表所示,web自动化就是靠着HTML的各种标签、属性等来定位元素来进行操作,那么这些定位方式怎么理解?我们可以参考一个犯罪案例:
警察正在抓捕一名人犯罪嫌疑人,要确认犯罪嫌疑人的身份就可以根据嫌疑人的姓名、别名、指纹、身份证号、手机号等可识别区分的属性;同样的,元素自身也有id
、classname
、tagname
、name
等属性可用于区分定位;
此嫌疑人的反侦察能力比较强,隐藏了自己的身份特征,无法根据其自身的属性进行定位,那么就可以根据其经常出没的场所来进行定位抓捕,例如去某省某市的某个酒吧里,去某县某村某号的一个住所去;同样的,元素自身也可以通过Xpath
和CSS
这种标签的层级位置来定位元素。
到目前为止,嫌烦依然在逃,为了躲避侦查,曾经的常去场所都不再接触,高手!这是高手!苦苦的等待,最终办案民警们终于有了线索(接下来该办案民警出场讲述转机了~):由于犯罪嫌疑人是个大孝子且十分疼爱自己的妻儿,于是在某个地方偷偷的给父母通了电话,去学校见了妻儿;最终根据其家人提供的信息暴露自己,被定位抓获!同样的,元素也可以通过与其相关的元素来进行定位,我们就可以用CSS
或Xpath
来进行父子,兄弟等节点位置的方式来进行定位了。
Warning! 下面在介绍各种定位方式的时候还会顺便补充CSS的定位方式作为对比,首次接触的话可能会因为看不懂而引起不适,不用担心,可以先忽略,后面会专门介绍CSS的,待了解了CSS定位方式后再回来学习
testerhome
首页右上角的欢迎
,如下图:WebDriver driver = new ChromeDriver();
driver.findElement(By.id("cornertip"));
driver.findElement(By.cssSelector("#cornertip")); //CSS
小技巧:我们可以在Chrome
的开发者工具中Control+F
搜索框中对我们要定位的元素进行搜索来确认定位是否正确,支持CSS
和xpath
,如上图所示
testerhome
首页的搜索框,就可以根据ClassName
,如下图:WebDriver driver = new ChromeDriver();
driver.findElement(By.className("form-control"));
driver.findElement(By.cssSelector(".form-control")); //CSS
name
和CSS
定位:WebDriver driver = new ChromeDriver();
driver.findElement(By.className("q"));
driver.findElement(By.cssSelector("[name='q']")); //CSS
testerhome
首页的搜索框,通过tagname
:input
来定位WebDriver driver = new ChromeDriver();
driver.findElement(By.tagName("input"));
driver.findElement(By.cssSelector("input")); //CSS
linktest
和CSS
:WebDriver driver = new ChromeDriver();
driver.findElement(By.linkText("[深圳][头条] 招聘测试 leader"));
driver.findElement(By.cssSelector("a[title='[深圳][头条] 招聘测试 leader']")); //CSS
WebDriver driver = new ChromeDriver();
driver.findElement(By.partialLinkText("[深圳][头条]"));
driver.findElement(By.cssSelector("[title~='[深圳][头条]']")); /CSS
有时候我们的页面元素被遮挡导致无法定位,需要滚动屏幕进行可视化,便可以用JS来操作:
((JavascriptExecutor)(driver)).executeScript("window.scroll(0, 1200)");
XPath
是一门在 XML 文档中查找信息的语言。XPath
可用来在XML
文档中对元素和属性进行遍历,而HTML
又正好可以看做是XML
的一种实现,因此我们便可以用xpath
来定位元素啦
问题:一般刚开始学定位的时候很多人都会想,都有了上面那么多种定位方式了,还要xpath
干吗?感觉还挺复杂的样子(和其他的定位方式相比却是要复杂那么一丢丢)~
答: 那是因为并不是所有的元素都“如您所愿”,就如上面警察抓捕罪犯的例子,有时候元素并不能直接提供给我们想要的定位属性
常用路径表达式:
表达式 | 描述 |
---|---|
nodename | 选取此节点的所有子节点。 |
/ | 从根节点选取。 |
// | 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。 |
. | 选取当前节点。 |
… | 选取当前节点的父节点。 |
@ | 选取属性。 |
举几个简单的栗子
1)绝对路径定位
做测试开发或者有编程经验的小伙伴一定对绝对路径不陌生,通过绝对路径就是使用元素在页面上的完整路径、
还是以定位一周内的最热门帖子为例,在Chrome浏览器的开发者工具栏中,找到要定位元素的HTML位置,右击会出现Copy full Xpath
,点击它
然后我们把复制到的内容黏贴后如下:
/html/body/div[2]/div[2]/div/div[2]/div[1]/div[2]/div[1]/div/a
写到代码里就是这样:
WebDriver driver = new ChromeDriver();
driver.findElement(By.xpath("/html/body/div[2]/div[2]/div/div[2]/div[1]/div[2]/div[1]/div/a"));
可以用又臭又长来形容了,那么细心的小伙伴会发现还有一个Copy xpath
,复制黏贴后内容如下:
//*[@id="main"]/div/div[2]/div[1]/div[2]/div[1]/div/a
看起来好像简化了点,还用上了xpath
的语法,但是实际上也没优化多少,依然是通过标签的层级关系,从最外层一级一级的往下找,也不是很可取;
其实不可取的最主要原因还是这种绝对路径
的方式在实际自动化过程中很不稳定,界面的位置发生任何一丢丢的变化,那元素的绝对路径就很可能变了,也就无法准确定位了。
因此我们就要用元素的属性
或者属性和层级关系
相结合的方式来定位,这样就算页面变化,只要变化不是非常大,依然可以通过元素的属性和相对的位置来进行定位,受页面位置变化的影响就要小的多了
2)元素属性定位
testerhome
首页的欢迎
,利用xpath
语法通过id
来定位:WebDriver driver = new ChromeDriver();
driver.findElement(By.xpath("//div[@id='c-button']"));
语法解释://div
表示从当前页面的div
标签开始匹配,@id
表示用id属性值,=
后面跟着具体的id
值3)属性和层级关系定位
上面的通过属性定位完全可以用WebDriver
的API
或者CSS
搞定,xpath
最大的价值就是上面说的当元素没有直接可定位的属性时,它的价值才得以完美体现:
七日最热 Top10
“这个标题,它只有class
属性,我们按照className
来进行定位会发现如下情况:classname
,并且没有其他如id
,name
等属性了;div
标签节点,classname
为”col-md-3 home-side-bar
“的标签节点是唯一的:Xpath
先定位到唯一的那个class
,然后往下找两层div
,再取两层后div
中的第一个就可以了WebDriver driver = new ChromeDriver();
driver.findElement(By.xpath("//*[@class='col-md-3 home-side-bar']/div[1]/div[1]"));
4)使用Xpath运算符定位
Xpath还支持运算符,如果元素的一个属性无法定位,需要使用多个属性时可以使用Xpath运算符将多个属性连接起来一起定位
Xpath常用运算符
运算符 | 描述 | 实例 | 返回值 |
---|---|---|---|
| |
计算两个节点集 | //book | //cd |
返回所有拥有 book 和 cd 元素的节点集 |
or | 或 | price=9.80 or price=9.70 | 如果 price 是 9.80,则返回 true。如果 price 是 9.50,则返回 false。 |
and | 与 | price>9.00 and price<9.90 | 如果 price 是 9.80,则返回 true。如果 price 是 8.50,则返回 false。 |
现在需要定位testhome
社区首页一篇最新帖子的作者,作者名为“乌云乌云快走开”
如果我们只依靠className
的话会发现有28个相同属性的元素,如下图:
继续观察会发现还有一个叫做data-name
的属性,属性值就是作者的姓名,我们通过and符将两个属性连接后便发现可以精准定位到指定元素了:
WebDriver driver = new ChromeDriver();
driver.findElement(By.xpath("//a[@class='user-name' and @data-name='乌云乌云快走开']"));
5)使用Xpath函数定位
Xpath还提供了很多函数来供我们更灵活的定位,这里以我常用的一个contains
函数为例
testerhome
首页七日最热贴的首贴“[深圳][头条] 招聘测试 leader”,通过对DOM的分析可以看到title
属性的内容就是帖子的标题,我们用此属性值的一部分来作为定位条件:WebDriver driver = new ChromeDriver();
driver.findElement(By.xpath("//*[contains(@title,'[深圳][头条]')]"));
关于Xpath的语法使用还有很多,包括还有很多函数,具体的可参考W3C进行学习:
https://www.w3school.com.cn/xpath/xpath_syntax.asp
Web页面的样式通常保存在外部的 .css 文件中。通过仅仅编辑一个简单的 CSS 文档,外部样式表使你有能力同时改变站点中所有页面的布局和外观。因此我们可以利用CSS的选择器来定位页面绑定了属性的元素,从而为我们的selenium所用
从上面的文章一路看下来的小伙伴应该发现了,在介绍xpath
之前的定位方式时,都另外还写了一个CSS
的定位方式,没错,就是它,没注意的小伙伴可以返回去看一看;
推荐使用CSS:
CSS
也是我们在Web自动化中最推荐使用的一种方式,原因又如下几种:
id
这种元素在一个页面中可能并不唯一,并且很有可能是前端的框架自动生成的,研发人员并未对其进行维护,随时可能变;而CSS
是前端开发最常用的一种维护方式,对于我们开发和维护自动化用例也更为清晰和方便CSS
来解决CSS
的写法相较于Xpath
要更为简洁常用的CSS选择器语法:
选择器 | 例子 | 例子描述 |
---|---|---|
.class | .intro | 选择 class=“intro” 的所有元素。 |
#id | #firstname | 选择 id=“firstname” 的所有元素。 |
* | * | 选择所有元素。 |
element | p | 选择所有 元素。 |
element,element | div,p | 选择所有
|
element element | div p | 选择
|
element>element | div>p | 选择父元素为
|
element+element | div+p | 选择紧接在
|
[attribute] | [target] | 选择带有 target 属性所有元素。 |
[attribute=value] | [target=_blank] | 选择 target="_blank" 的所有元素。 |
[attribute~=value] | [title~=flower] | 选择 title 属性包含单词 “flower” 的所有元素。 |
先将前面已经演示过的CSS
语法在这来个小的汇总:
id
WebDriver driver = new ChromeDriver();
driver.findElement(By.cssSelector("#cornertip")); //CSS
className
WebDriver driver = new ChromeDriver();
driver.findElement(By.cssSelector(".form-control"));
name
WebDriver driver = new ChromeDriver();
driver.findElement(By.cssSelector("[name='q']"));
tag name
WebDriver driver = new ChromeDriver();
driver.findElement(By.cssSelector("input"));
link text
WebDriver driver = new ChromeDriver();
driver.findElement(By.cssSelector("a[title='[深圳][头条] 招聘测试 leader']"));
partialLinkText
WebDriver driver = new ChromeDriver();
driver.findElement(By.cssSelector("[title~='[深圳][头条]']"));
WebDriver driver = new ChromeDriver();
driver.findElement(By.cssSelector(".panel-heading+div>div>div.topic-20857"));
简要说明:
.panel-heading
:class值为panel-heading
+div
: 后面紧接着的div
>div
:后面所有子的div
div.topic-20857
:class名为topic-20857的div标签
更多细节和用法可参考W3C进行学习:
https://www.w3school.com.cn/cssref/css_selectors.asp
参考文档:
selenium官网:https://www.seleniumhq.org/docs/03_webdriver.jsp