前言:

使用 selenium 已经好几个年头,从开始使用 selenium ide 录制、到手动编写脚本、到使用 execl 管理关键字驱动用例,到今年通过 python、flask、mysql、docker 搭建为一个部门内通用的自动化测试管理平台,觉得有必要把一些常见问题和技巧总结一下。

1 常用的元素定位方式

以百度首页为例,输入框、搜索按钮几个元素对应的 HTML 代码分别如下:(可在页面中右键》查看元素,或在浏览器中按 F12 打开开发模式查看元素)

搜索输入框:
<input id="kw" name="wd" class="s_ipt" value="" maxlength="255" autocomplete="off">

“百度一下”按钮:
<input type="submit" id="su" value="百度一下" class="bg s_btn">

1.1 首选 id

使用元素的 id, 是最便利,也是最稳定的一种元素识别方式。所以在看到元素源代码包含 id 时,首先考虑使用 id。
如上面的搜索输入框、搜索按钮,分别有对应的 id : kw、 su。

举例:在输入框中输入 “selenium test”,并点击搜索按钮进行搜索:

driver.find_element_by_id("kw").send_keys("selenium test")
driver.find_element_by_id("su").click()

开发人员在开发时未必会给每一个元素都加上 id ,所以我们会遇到一些无法使用 id 定位的元素。
这种情况下,可根据元素的具体情况使用不同的方法进行定位。

如百度首页右上有新闻、地图、视频等链接。查看源码,这些链接是没有 id 的:

<a href="http://news.baidu.com" name="tj_trnews" class="mnav">新闻</a>
<a href="http://www.hao123.com" name="tj_trhao123" class="mnav">hao123</a>
<a href="http://map.baidu.com" name="tj_trmap" class="mnav">地图</a>
<a href="http://v.baidu.com" name="tj_trvideo" class="mnav">视频</a>
<a href="http://tieba.baidu.com" name="tj_trtieba" class="mnav">贴吧</a>
<a href="http://xueshu.baidu.com" name="tj_trxueshu" class="mnav">学术</a>
<a href="https://passport.baidu.com/v2/?login&amp;tpl=mn&amp;u=http%3A%2F%2Fwww.baidu.com%2F&amp;sms=5" name="tj_login" class="lb" onclick="return false;">登录</a>
<a href="http://www.baidu.com/gaoji/preferences.html" name="tj_settingicon" class="pf">设置</a>
<a href="http://www.baidu.com/more/" name="tj_briicon" class="bri" style="display: block;">更多产品</a>

我们要找到一个只有这个元素才有的属性来进行定位:

如上面每个元素都有一个对应的 name 属性,如:tj_trnews 。 这个属性值如果是唯一的(即在当前页面只有一个元素的 name = tj_trnews),则定位起来也非常方便和稳定。 同理,可以用多种不同的方式定位上的元素:

 通过name 定位 《新闻》 链接:
driver.find_element_by_name("tj_trnews").click()

通过link text 定位 《新闻》 链接:
driver.find_element_by_link_text("新闻").click()

通过partial link text 定位 《新闻》 链接 ,与link text 的区别在于完全匹配和模糊匹配:
driver.find_element_by_partial_link_text("新闻").click()

通过class 定位 《设置》 链接:
注:有些元素的 class 是相同的,此时未必能定位到同一个元素;另外有些元素的class属性是复合型的,如:
class="fa fa-eye",这时需要选择其中一个属性来进行定位。

driver.find_element_by_class_name("pf").click()
driver.find_element_by_class_name("fa-eye").click()

1.3 使用 css、xpath 定位元素

css 、xpath 是根据页面结构位置来定位元素的方式。如在 chrome 浏览器的开发模式中,选择对应节点,右键 copy ,可看到 copy selector 和 copy xpath 的两个选项,对应的就是复制当前元素对应的 css 和 xpath 路径。

selenium 中对应的使用方式:

css: 
driver.find_element_by_css_selector("#u1 > a.pf").click()

xpath:
driver.find_element_by_xpath('//*[@id="u1"]/a[8]').click()

注意:
由于 css 、 xpath 是根据页面的结构查找元素的,所以存在以下问题:

  1. 查找速度和性能:如果页面结构很复杂时,查找速度可能会比较慢。
  2. 不稳定:如果页面布局发生变化,对应的 css 、xpath 可能无法识别。

1.4 建议使用原则:

  1. 首选 id 。
  2. 如果没有 id,找一个能单独找到该元素的属性进行定位(name、class 等)。
  3. 以上方式都不可用的情况下,使用 css、xpath 。

2 常见问题和技巧:

2.1 无法找到元素?可能元素在 iframe 中。

有时会发现,有时明明已使用元素唯一的属性(如 id、name),执行时却提示无法找到元素。

这时可以检查一下,页面元素是否存在在 iframe(html 中的一个内联框架)中。

<div id="iframewrapper">
    <iframe frameborder="0" id="iframeResult" style="height: 643.96px;">
        <title>iframe</title>
        <input type="submit" id="bt1" value="iframe中的按钮" class="bg s_btn btnhover">
    </iframe></div>
<input type="submit" id="su" value="主页面的按钮" class="bg s_btn btnhover">

例如上面的 html 代码,页面上分别有 bt1 和 bt2 两个按钮,其中 bt1 是在 frame iframeResult 中,bt2 是在主页面。

这时,如果直接点击 bt1, 是无法找到元素的,必须先切换到 iframe 中:

先切换到目标iframe,其中 iframeResult 是目标iframe 的id:
driver.switch_to.frame("iframeResult")
然后再操作iframe中的元素:
driver.find_element_by_id("bt1").click()

如果再操作主页面的元素,需要切换回主页面:
driver.switch_to.default_content()
然后再操作主页面的元素:
driver.find_element_by_id("bt2").click()

一些通用的页面元素,如一些通用的按钮:“查询”、“新增” 等,或者是公共的菜单导航等,可以直接使用 link text 进行定位。这样不需要每个页面的按钮和菜单都逐个查看对应的 html 代码,而且测试用例中对步骤更为清晰明了。

如:

# 点击两级菜单:
driver.find_element_by_partial_link_text("系统管理").click()
driver.find_element_by_partial_link_text("数据字典").click()

...

# 输入查询条件后,点击查询按钮。  注意这里的查询由于样式设计,中间有空格,填写到脚本中时一定要复制完整。
driver.find_element_by_partial_link_text("查 询").click()

注意:如果菜单、按钮无法定位,要留意是否已复制了完整的文本,中间是否有空格存在。

2.3 选择框处理

selenium 提供了对选择框的多种选择方法。

如以下是一个 select 组件:

<select id="select1">
<option index="0"  value="volvo">Volvo</option>
<option index="1"  value="saab">Saab</option>
<option index="2"  value="mercedes">Mercedes</option>
<option index="3"  value="audi">Audi</option>
</select>

操作方式可以有:

from selenium.webdriver.support.select import Select
按选项的index 值选择
Select(driver.find_element_by_id('select1')).select_by_index('1')

按选项的value 值选择
Select(driver.find_element_by_id('select1')).select_by_value('saab')

按选项的文本选择
Select(driver.find_element_by_id('select1')).select_by_visible_text('Saab')

2.4 添加重试机制

用例步骤重试:如果某个步骤执行不成功(一般而言是元素没找到),建议重试 2-3 次。这样可以提高用例执行的稳定性。

用例执行重试:一条用例执行失败,有可能和当时的网络环境等相关。建议在失败后,重试 2-3 次,降低类似的误报率。

2.5 模拟手机浏览器

通过 chrome option 进行模拟

2.6 调用不同浏览器进行兼容性测试

在初始化 driver 时,选择不同的浏览器类型进行测试。

2.7 通过 selenium grid 进行分布式远程调用。


# 根据runtype 选择浏览器类型; 根据 devicename 选择需要模拟的手机型号
     if runType == 'Chrome':
            desired_caps_web = webdriver.DesiredCapabilities.CHROME
            deviceList = ['Galaxy S5', 'Nexus 5X', 'Nexus 6P', 'iPhone 6', 'iPhone 6 Plus', 'iPad', 'iPad Pro']
            if devicename!='' :
                if devicename not in deviceList:
                    devicename = deviceList[2]
                    chrome_option = {
                        'args': ['lang=en_US','start-maximized'],
                        'extensions': [], 'mobileEmulation': {'deviceName': ''}

                    }
                    chrome_option['mobileEmulation']['deviceName'] = devicename
            else:
                chrome_option = {
                        'args': ['lang=en_US','--start-maximized'],
                        'extensions': []
                    }
            desired_caps_web['goog:chromeOptions']=chrome_option
    elif runType == 'Firefox':
            desired_caps_web = webdriver.DesiredCapabilities.FIREFOX

# 初始化            
    server_url = 'http://172.16.70.12:4444/'
    driver = webdriver.remote.webdriver.WebDriver(command_executor=server_url,desired_capabilities=desired_caps_web)

2.8 使用 docker 运行不同的 selenium 服务节点。

这里不展开。


↙↙↙阅读原文可查看相关链接,并与作者交流