对象(元素)的定位和操作是自动化测试的核心部分,其中操作又是建立在定位的基础上的,因此元素定位就显得非常重要。(这里用到的对象与元素同为一个事物)
一个对象就像是一个人,他会有各种的特征(属性),如比我们可以通过一个人的身份证号、姓名或者他的住址找到这个人。那么一个元素也有类似的属性,我们可以通过这种唯一区别于其它元素的属性来定位这个元素。当然,除了要操作元素时需要定位元素外,有时候我们只是为了获得元素的属性(class 属性,name 属性)、text 或数量也需要定位元素。
webdriver 提供了一系列的元素定位方法,常用的有以下几种:
id
name
class name
tag name
link text
partial link text
xpath
css selector
分别对应python webdriver 中的方法为:
find_element_by_id()
find_element_by_name()
find_element_by_class_name()
find_element_by_tag_name()
find_element_by_link_text()
find_element_by_partial_link_text()
find_element_by_xpath()
find_element_by_css_selector()
这里主要介绍CSS定位
CSS(Cascading Style Sheets)是一种语言,它被用来描述HTML 和XML 文档的表现。CSS 使用选择器来为页面元素绑定属性。这些选择器可以被selenium 用作另外的定位策略。
CSS 可以比较灵活选择控件的任意属性,一般情况下定位速度要比XPath 快,但对于初学者来说比较难以学习使用,下面我们就详细的介绍CSS 的语法与使用。
CSS 选择器的常见语法:
* | 通用元素选择器,匹配任何元素 |
E | 标签选择器,匹配所有使用E 标签的元素 |
.info | class 选择器,匹配所有class 属性中包含info 的元素 |
#footer | id 选择器,匹配所有id 属性等于footer 的元素 |
E,F | 多元素选择器,同时匹配所有E 元素或F 元素,E 和F 之间用逗号分隔 |
E F | 后代元素选择器,匹配所有属于E 元素后代的F 元素,E 和F 之间用空格分隔 |
E > F | 子元素选择器,匹配所有E 元素的子元素F |
E + F | 毗邻元素选择器,匹配紧随E 元素之后的同级元素F (只匹配第一个) |
E ~ F | 同级元素选择器,匹配所有在E 元素之后的同级F 元素 |
E[att='val'] | 属性att 的值为val 的E 元素(区分大小写) |
E[att^='val'] | 属性att 的值以val 开头的E 元素(区分大小写) |
E[att$='val'] | 属性att 的值以val 结尾的E 元素(区分大小写) |
E[att*='val'] | 属性att 的值包含val 的E 元素(区分大小写) |
E[att1='v1'][att2*='v2'] | 属性att1 的值为v1,att2 的值包含v2 (区分大小写) |
E:contains('xxxx') | 内容中包含xxxx 的E 元素 |
E:not(s) | 匹配不符合当前选择器的任何元素 |
例如下面一段代码:
<div class="formdiv">
<form name="fnfn">
<input name="username" type="text"></input>
<input name="password" type="text"></input>
<input name="continue" type="button"></input>
<input name="cancel" type="button"></input>
<input value="SYS123456" name="vid" type="text">
<input value="ks10cf6d6" name="cid" type="text">
</form>
<div class="subdiv">
<ul id="recordlist">
<p>Heading</p>
<li>Cat</li>
<li>Dog</li>
<li>Car</li>
<li>Goat</li>
</ul>
</div>
</div>
通过CSS 语法进行匹配的实例:
locator | 匹配 |
---|---|
css=div css=div.formdiv | <div class="formdiv"> |
css=#recordlist css=ul#recordlist | <ul id="recordlist"> |
css=div.subdiv p css=div.subdiv > ul > p | <p>Heading</p> |
css=form + div | <div class="subdiv"> |
css=p + li css=p ~ li | 二者定位到的都是<li>Cat</li> 但是storeCssCount 的时候,前者得到1,后者得到4 |
css=form > input[name=username] | <input name="username"> |
css=input[name$=id][value^=SYS] | <input value="SYS123456" name="vid" type="hidden"> |
css=input:not([name$=id][value^=SYS]) | <input name="username" type="text"></input> |
css=li:contains('Goa') | <li>Goat</li> |
css=li:not(contains('Goa')) | <li>Cat</li> |
css 中的结构性定位
结构性定位就是根据元素的父子、同级中位置来定位,css3标准中有定义一些结构性定位伪类如nth-of-type,nth-child,但是使用起来语法很不好理解,这里就不做介绍了。
Selenium 中则是采用了来自Sizzle 的css3定位扩展,它的语法更加灵活易懂。Sizzle Css3的结构性定位语法:
E:nth(n) E:eq(n) | 在其父元素中的E 子元素集合中排在第n+1 个的E 元素(第一个n=0) |
E:first | 在其父元素中的E 子元素集合中排在第1 个的E 元素 |
E:last | 在其父元素中的E 子元素集合中排在最后1 个的E 元素 |
E:even | 在其父元素中的E 子元素集合中排在偶数位的E 元素(0,2,4…) |
E:odd | 在其父元素中的E 子元素集合中排在奇数的E 元素(1,3,5…) |
E:lt(n) | 在其父元素中的E 子元素集合中排在n 位之前的E 元素(n=2,则匹配0,1) |
E:gt(n) | 在其父元素中的E 子元素集合中排在n 位之后的E 元素(n=2,在匹配3,4) |
E:only-child | 父元素的唯一一个子元素且标签为E |
E:empty | 不包含任何子元素的E 元素,注意,文本节点也被看作子元素 |
例如下面一段代码:
<div class="subdiv">
<ul id="recordlist">
<p>Heading</p>
<li>Cat</li>
<li>Dog</li>
<li>Car</li>
<li>Goat</li>
</ul>
</div>
匹配示例:
locator | 匹配 |
css=ul > li:nth(0) | <li>Cat</li> |
css=ul > *:nth(0) css=ul > :nth(0) | <p>Heading</p> |
css=ul > li:first | <li>Cat</li> |
css=ul > :first | <p>Heading</p> |
css=ul > *:last css=ul > li:last | <li>Goat</li> |
css=ul > li:even | Cat, Car |
css=ul > li:odd | Dog, Goat |
css=ul > :even | <p>Heading</p> |
css=ul > p:odd | [error] not found |
css=ul > li:lt(2) | <li>Cat</li> |
css=ul > li:gt(2) | <li>Goat</li> |
css=ul > li:only-child css=ul > :only-child css=ul > *:only-child | [error] not found (ul 没有only-child) |
css=div.subdiv > :only-child | <ul id="recordlist"> … … … … </ul> |