• 面试准备——(三)Selenium面试题总结


    一、Selenium基本知识

    1. 什么是Selenium?

    Selenium是浏览器自动化工具,主要用来Web的自动化测试,以及基于Web的任务管理自动化。它支持的语言有:python、Java、ruby、JavaScript等,并且几乎能在主流的浏览器上运行。

    Selenium2.0、Selenium3.0主要由三大部分组成:SeleniumIDE、Selenium WebDriver、Selenoium Grid。

    • Selenium IDE录制和回放脚本,可以模拟用户对页面的真实操作,区别于其他工具:是通过拦截http请求
      • 一般只把录制脚本当作一个辅助功能,因为一个UI节点的细微变化,都可能导致自动化测试工具无法识别,当测试项目项目大时,定位、更新十分困难。
      • 其次,录制的脚本有时候人工难以理解。
    • Selenium Grid实现在多台机器上、和异构环境中并行执行测试用例。并行执行不仅节省时间,而且可以同时在不同的浏览器、平台上运行自动化测试脚本。
    • Selenium Web Driver:针对各个浏览器而开发,通过原生浏览器支持或者扩展(Chrome webDrive、FireFox WebDriver)直接控制浏览器

        VS Selenium RC(Selenium1.0):在浏览器中运行javaScript,使用浏览器内置的JavaScript来翻译和执行selense

    Web Driver原理

    webDriver是按照client/server模式设计的。client是我们的测试脚本,发送请求;server就是打开的浏览器,用来接收client的请求并作出响应。

    具体的工作流程:

    1. webDriver打开浏览器并绑定到指定端口。启动的浏览器作为远程服务器remote server
    2. client通过CommandExecuter发送http请求给远程服务器的侦听端口(the wire protocal)
    3. 远程服务器根据原生的浏览器组件来转化为浏览器的本地(native)调用

    web Driver用到的协议

    1. 打开浏览器时:HTTP协议
    2. client端发送http请求到远程服务器的侦听端口:the wire protocol

    其中:

    • 有线协议:指的是从点到点获取数据的方式,是应用层的协议。
    • HTTP协议:是用于从服务器传输超文本标记语言HTML到客户端的通信协议。是一个应用层协议,由请求/响应构成,是一个标准的客户/服务器模式。是一个无状态的协议。(无状态:对事务没有记忆能力,不会保存这次传输的信息——节约内存)

    2. Selenium的特点有:

    • 支持录制和回放(Selenium IDE)
    • 通过WebDriver,直接控制浏览器,而不是通过拦截HTTP请求,实现真正模仿了用户的操作;同时使用WebDriver能够灵活的获取页面元素(WebDriver),并且提供执行JS的接口
    • 能够分布式运行在不同机器和异构环境中(不同浏览器)

    3. Selenium的内部运行机制?如何能够跨浏览器使用?——WebDriver原理(&RC原理)

    1)RC原理

    在Selenium1.0中,是通过Selenium RC服务器作为代理服务器去访问应用从而达到测试的目的。

    Selenium RC分为三个部分,Launcher、HttpProxy、Core。

    • Launcher用于启动浏览器,把Selenium Core加载到浏览器中,并且把浏览器的代理设置为Selenium Server的Http Proxy。
    • Core是一堆JavaScript的集合,所以本质相当于运行这些JavaScript函数来实现对Html页面的操作。——这也是为什么可以运行在几乎所有主流的浏览器上。

    然而直接运行JavaScript会有极大的安全漏洞,所以会受到“同源限制”,在这个基础上,Selenium2.0引入了WebDriver。

    2)Web Driver原理

    webDriver是按照client/server模式设计的。client是我们的测试脚本,发送请求;server就是打开的浏览器,用来接收client的请求并作出响应。

    具体的工作流程:

    1. webDriver打开浏览器并绑定到指定端口。启动的浏览器作为远程服务器remote server
    2. client通过CommandExecuter发送http请求给远程服务器的侦听端口(the wire protocal)
    3. 远程服务器根据原生的浏览器组件来转化为浏览器的本地(native)调用

    所以web Driver用到的协议

    1. 打开浏览器时:HTTP协议
    2. client端发送http请求到远程服务器的侦听端口:the wire protocol

    其中:

    • 有线协议:指的是从点到点获取数据的方式,是应用层的协议。
    • HTTP协议:是用于从服务器传输超文本标记语言HTML到客户端的通信协议。是一个应用层协议,由请求/响应构成,是一个标准的客户/服务器模式。是一个无状态的协议。(无状态:对事务没有记忆能力,不会保存这次传输的信息——节约内存)

    4. 如何提高selenium脚本的执行速度?

    1)优化测试用例。

    • 尽可能不用sleep、减少使用implicityWait,而使用WebDriverWait/FluentWait,这样可以优化等待时间
    • 减少不必要的操作步骤。

    2)使用Selenium grid,通过testNG实现并发执行。 

    说到这里,在编写测试用例的时候,一定要实现松耦合,然后再服务器允许的情况下,尽量设置多线程实现并发运行。

    3)设置等待时间、中断页面加载。如果页面加载内容太多,我们可以查看一下加载缓慢的原因,在不影响测试的情况下,可以设置超时时间,中断页面加载。

     

    5. 提高自动化脚本稳定性——减少误报

    1. 误报问题。我们一旦测试用例没有通过,则无法完成每日自动构建,但是其实这些测试用例是正确,也不存在BUG。

    2. 主要的原因页面还没有加载完成,我们就开始进行元素定位。

    3. 解决方法重试机制。利用递归封装了一个等待元素的方法。其中,设置最大等待时间为1s,轮询时间为50ms,这个方法会不断轮询,直到方法执行成功或者超过设置的最大等待时间。在我们最好的一次实践中,我们把一个测试用例的误报率从10%降低到0,并且执行时间从原先的45秒降低到33秒。

    6. 如何设计高质量自动化脚本

    1. 使用四层结构实现业务逻辑、脚本、数据分离。

    2. 使用PO设计模式,将一个页面用到的元素和操作步骤封装在一个页面类中。如果一个元素定位发生了改变,我们只用修改这个页面的元素属性

    3. 对于页面类的方法,我们尽量从客户的正向逻辑去分析,方法中是一个独立场景,例如:登录到退出,而且不要想着把所有的步骤都封装在一个方法中。

    4. 测试用例设计中,减少测试用例之间的耦合度。

    7. 你觉得自动化测试最大的缺陷是什么?

    1. 一旦项目发生变化,测试用例就需要改进,工作量大。

    2. 验证的范围有限,操作更加复杂,比如说简单的一个验证验证码,如果是人工识别很快就可以输入,但是自动化测试中会增添很多困难。那么这个时候速度也不如人工。

    3. 不稳定

    4. 可靠性不强

    5. 成本与收益

    二、元素定位

    1. ElementNotVisible

    1. selenium中hidden或者是display = none的元素是否可以定位到?——用Js修改display = block

    1)区分:display= none VS hidden

    共同点:都把网页中的元素给隐藏起来了;在selenium中无法直接定位

    区别:none:不为隐藏的对象保留其物理空间 看不见/摸不着

       hidden仍占有空间 看不见/摸得着

    1. 处理 display:none

    页面主要通过"dislay:none"来控制整个下拉框不见。如果直接操作:

    from selenium.webdriver.support.ui import WebDriverWait
    from selenium import webdriver
    from selenium.webdriver.support.select import Select
    import os
    
    driver = webdriver.Firefox(executable_path="/Users/lesley/Downloads/geckodriver")
    file_path = 'file:///' + os.path.abspath('test.html')
    driver.get(file_path)
    
    select = driver.find_elements('select')
    Select(select).select_by_value('volvo')
    WebDriverWait()
    
    driver.quit()

    报错:ElementNotVisible

    我们可以通过JavaScript来修改display的值

    js = 'document.querySelectortAll('select')[0]'.style.display='block';'
    
    select = driver.find_element_by_tag_name('select')
    Select(select).select_by_value('Opel')

    document.querySelectAll('select'):选择所有的select;[0]表示第几个

    style.display='block':修改display=block,表示可见

    2. NoSuchElementException

    首先,判断一个元素是否显示:is_displayed()

    1. Frame/IFrame原因定位不到元素——switch_to_iframe

    frame是指:页面中嵌入另一个页面,而webdriver每次只能在一个页面识别,因此需要先定位到相应的frame,对那个页面里的元素进行定位。

    此时,有两种方式:

    1. iframe存在id 或者name。

    首先用switch_to_frame('x-URS-iframe')定位到这个iframe,然后再定位这个iframe中的元素

    driver=webdriver.Firefox()
    driver.get(r'http://www.126.com/')
    driver.switch_to_frame('x-URS-iframe')  #需先跳转到iframe框架
    username=driver.find_element_by_name('email')
    username.clear()

    2.  iframe不存在name/id。

    先定位到iframe,再swith_to_frame

    #先定位到iframe
    elementIframe= driver.find_element_by_class_name('APP-editor-iframe')
    #再将定位对象传给switch_to_frame()方法
    driver.switch_to_frame(elementIframe) 

    如果完成操作后,可以通过switch_to_parent_content()方法跳出当前iframe,或者还可以通过switch_to_default_content()方法跳回最外层的页面。

    2. 页面没有加载出来,就对页面中元素进行操作。

    ——设置等待时间直到元素出现(WebDriveWait(driver,10).until(lambda x:x.find_elemetn_by_id('someId').is_displayed)

    获取页面加载状态

    document.readyState

    例如:当Selenium点击一个按钮打开一个弹窗,弹窗还没有打开的时候,我们就要使用弹窗上一个按钮。

    ——>解决:设置等待最大等待时间

    1)sleep():设置固定休眠时间

    2)implicity_wait():是webDriver提供的一个超时等待,隐的等待一个元素被发现,或者一个命令完成

    3)WebDriverWait():同样也是WebDriver提供的方法。在设置时间内,默认每隔一段时间检测一次当前页面元素是否存在,如果超出指定时间检测不到则抛出异常。

    WebDriverWait(driver, timeout, poll_frequency=0.5, ignored_exceptions=None)
    
    # driver:WebDriver的驱动程序
    # timeout:最长超时时间,默认以秒为单位
    # poll_frequency:休眠时间的间隔时间
    # ignore_exception():超时后的异常信息,默认情况下抛出NoSuchElementException

    通常与until()或者until_not()方法配合使用

    until(method, message="")
    # 调用该方法提供的驱动程序作为一个参数,直到返回值不为FALSE
    
    until_not(method, message="")
    # 调用该方法提供的驱动程序作为一个参数,直到返回值为FALSE

     举例:

     1 from selenium.webdriver.support.ui import WebDriverWait
     2 
     3 from selenium import webdriver
     4 import time
     5 
     6 driver = webdriver.Firefox(executable_path="/Users/lesley/Downloads/geckodriver")
     7 driver.get("https://www.baidu.com/")
     8 
     9 # 添加WebDriverWait
    10 element = WebDriverWait(driver, 10).until(lambda driver:driver.find_element_by_id("kw"))
    11 is_disappeared = WebDriverWait(driver, 5).until_not(lambda x: x.find_element_by_id("someId").is_displayed())
    12 element.send_keys("sbw")
    13 
    14 # 添加智能等待
    15 driver.implicitly_wait(5)
    16 driver.find_element_by_id("su").click()
    17 
    18 # 添加固定时间等待
    19 time.sleep(5)
    20 
    21 driver.quit()

    4)WaitFor:配合setTimeout,设置最大等待时间,然后轮询查看是否在指定时间内找到该元素。

    1 def waitfor(getter, timeout=3, interval=0.5, *args):
     2     starttime = datetime.datetime.now()
     3     while True:
     4         if getter(args):
     5             return
     6         else:
     7             runtime = datetime.datetime.now() - starttime
     8             print runtime
     9             if runtime.seconds >= timeout:
    10                 raise Exception
    11             time.sleep(interval)
    12     
    13 current_value = 1    
    14 def testgetval(args):
    15     wanted_value = args[0]
    16     global current_value
    17     current_value += 1
    18     print '%d, %d' % (wanted_value, current_value)
    19     return current_value > wanted_value    
    20         
    21 if __name__ == '__main__':
    22     waitfor(testgetval, 1, 0.3, 2)
    23     print '======================='
    24     waitfor(testgetval, 1, 0.3, 8)

    3. 动态ID无法定位元素——1)直接使用Xpath相对路径;2)根据部分元素定位

    如何判断是动态ID?

    简单,一般看到元素属性里有拼接一串数字的,就很有可能是动态的。想要分辨,刷新一下浏览器再看该元素,属性值中的数字串改变了,即是动态属性了。

    <div id="btn-attention_2030295">...</div>

    方式(一)根据相对路径

    http://blog.csdn.net/huilan_same/article/details/52541680

    方式(二)根据部分元素属性定位

    driver.find_element_by_xpath("//div[contains(@id, 'btn-attention')]")
    driver.find_element_by_xpath("//div[starts-with(@id, 'btn-attention')]")
    driver.find_element_by_xpath("//div[ends-with(@id, 'btn-attention')]")  # 这个需要结尾是‘btn-attention’

    4. 二次定位,如弹出登陆框

    ——层级定位

    # 点击打开菜单栏
    driver.find_element_by_xpath("//*[@id='sidebar-collapse']/i").click();
    
    # 点击菜单块
    driver.find_element_by_xpath("//*[@id='sidebar']/div[1]/ul/li[2]/a").click();
    
    # 点击“待办中心”
    driver.find_element_by_linkText("待办案件").click();

     

    5. 有两个属性相同的元素,但是其中一个是不可见的。——找到符合这个属性且style属性中display=none的元素

    driver.find_element_by_xpath("//span[contains(@id, 'sbw')] and not(contains[@style, 'display:none'])")

    6. Xpath描述错误

    1)通过属性定位元素

    find_element_by_xpath("//标签名[@属性='属性值']")

    例如:

    # id属性:
    driver.find_element_by_xpath("//input[@id='kw']")
    
    # class属性:
    driver.find_element_by_xpath("//input[@class='s_ipt']")
    
    # name属性:
    driver.find_element_by_xpath("//input[@name='wd']")
    
    # maxlength属性:
    driver.find_element_by_xpath("//input[@maxlength='255']")

    2)通过标签名

    driver.find_elment_by_xpath('//input')

    3)父子定位元素

    查找有父亲元素的标签名为span,它的所有标签名叫input的子元素

    driver.find_element_by_xpath("//span/input") 

    4)通过元素内容

    例如:

    <p id="jgwab">
        <i class="c-icon-jgwablogo"></i>
        京公网安备11000002000001号
    </p>

    则我们可以定位:

    # 根据text()
    driver.find_elment_by_xpath('//p[contains(text(), '京公网')]')
    
    # 根据class
    driver.find_elment_By_xpath('//p[contains(@class, '京公网')]')

    5. 组合定位元素

    //父元素标签名/标签名的属性值:指的是span下的input标签下class属性为s_ipt的元素

    driver.find_element_by_xpath("//span/input[@class='s_ipt']")

    6. 多个属性组合定位

    指的是input标签下id属性为kw且name属性为wd的元素

    driver.find_element_by_xpath("//input[@class='s_ipt' and @name='wd']")

    指的是p标签下内容包含“京公网”且id属性为jgwab的元素

    find_element_by_xpath("//p[contains(text(),'京公网') and @id='jgwab']") 

    三、常见控件使用

    1. link、button

    element.click()

    2. Textbox

    element.send_keys('test')

    3. Upload

    element.send_keys('D	est.txt')

    4. Mouse Event——ActionChains()

    #双击
    ActionChains(driver).double_click(element).perform()
    
    #右击
    ActionChains(driver).context_click(element).perform()
    
    #拖动
    ActionChains(driver).drag_and_drop(element).perform()
    
    #悬停
    ActionChains(driver).move_to_element(element).perform()

    5. DropDown:

    1)<Select>标签的下拉菜单

    from selenium.webdriver.support.ui import Select
    
    Select(driver.find_element_by_id('gender')).select_by_value('2')
    Select(driver.find_element_by_id('gender')).select_by_index(1)
    Select(driver.find_element_by_id('gender')).select_by_visible_text('Male')

    2)非<select>标签——层级定位

    Dropdown1 = driver.find_element_by_id(‘id’) #先定位到dropdown
    
    Dropdown1.find_element_by_id(“li2_input_2”) #再定位到dropdown中的值

     3)使用js实现:

    6. Alert

    driver.switch_to_alert().accept() # 接收弹窗
    driver.switch_to_alert().dismiss() # 取消弹窗
    
    # 获取弹窗的文本消息
    Message = driver.switch_to_alert().text

    7. Window

    driver.refresh() # 刷新
    
    driver.back() # 后退
    
    driver.forward() # 前进
    
    driver.maximize_window() # 最大化
    
    driver.set_window_size(100,200) # 设置窗口大小
    
    driver.switch_to.window(searchwindow)

    8. frame

    driver.switch_to.frame(ReferenceFrame)
    
    driver.switch_to.parent_frame()  # frame需要一级一级切
    
    driver.switch_to.default_content() # 返回最外层

    四、等待

    1. 显示等待——WebDriverWait()

    :等到某个条件成立时继续执行。每隔一段时间检测,超出最大时间则抛出异常

    is_disappeared = WebDriverWait(driver, 5).until_not(lambda x: x.find_element_by_id("someId").is_displayed())

    2.  隐式等待——implicitly_wait()

    隐式等待中的时间并非一个固定的等待时间,它并不影响脚本的执行速度。比如进行某元素的定位时,如果元素可以定位就继续执行,如果目前定位不到就以轮询的方式持续判断该元素是否被定位到,如果超过规定的时间还没定位到就抛出异常。

    driver.implicitly_wait(20)

    3. 强制等待——sleep()

    from time import sleep
    sleep(5)

     五、测试模型

    3. selenium中如何保证操作元素的成功率?也就是说如何保证我点击的元素一定是可以点击的?

    1. 首先通过封装find方法,实现wait_for_element_ispresent,这样在对元素进行操作之前保证元素被找到,进而提高成功率。(WebDriverWait)
    2. 在对页面进行click之前,先滚动到该元素(通过Js封装),避免在页面未加在完成前或是在下拉之后才能显示。

    4. Selenium有几种定位方式?你最偏爱哪一种,为什么?

    Selenium有八种定位方式

    1. 与name有关的有三种:name、class_name、tag_name
    2. 与link相关的有两种:link_text、partitial_link_text
    3. 与id有关:id
    4. 全能选手:xpath、css_selector

    如果存在id,我一定使用Id,因为简单方便,定位最快。其次是Xpath,因为很多情况下html标签的属性不够规范,无法唯一定位。Xpath是通过相对位置定位

    5. 如何去定位页面上动态加载的元素?

    首先触发动态事件,然后再定位。如果是动态菜单,则需要层级定位。——JS实现(对动态事件封装)

    http://www.cnblogs.com/tobecrazy/p/4817946.html 

    6. 如何去定位属性动态变化的元素?

    属性动态变化也就是指该元素没有固定的属性值可以通过:

    1. JS实现,
    2. 通过相对位置来定位,比如xpath的轴,paren/following-sibling/percent-sibling

    http://www.cnblogs.com/zhaozhan/archive/2009/09/10/1564332.html

    8. 点击链接以后,selenium是否会自动等待该页面加载完毕?

    不会的。所以有的时候,当selenium并未加载完一个页面时再请求页面资源,则会误报不存在此元素。所以首先我们应该考虑判断,selenium是否加载完此页面。其次再通过函数查找该元素。

      

    11. 如何在定位元素后高亮元素(以调试为目的)?

    12. 什么是断言?VS 验证

    1)断言(assert):测试将会在检查失败时停止,并不运行后续的检查

    优点:可以直截了当的看到检查是否通过

    缺点:检查失败后,后续检查不会执行,无法收集那些检查结果状态

    2)验证(vertify):将不会终止测试

    缺点:你必须做更多的工作来检查测试结果:查看日志——>耗时多,所以更偏向于断言

    # 断言验证:百度搜索的标题是否为:百度搜索
    # import unittest
    
    try:
        self.assertEqual(u"百度搜素", driver.title)
    except AssertionError as e:
        print("Cannot find this title")

    3)Waitfor:用于等待某些条件变为真。可用于AJAX应用程序的测试。

    如果该条件为真,他们将立即成功执行。如果该条件不为真,则将失败并暂停测试。直到超过当前所设定的超时时间。 一般跟setTimeout时间一起用。

    常用的断言:

     1 assertLocation          # 判断当前是在正确的页面
     2 assertTitle             #检查当前页面的title是否正确
     3 assertValue             # 检查input的值, checkbox或radio,有值为”on”无为”off”
     4 assertSelected          # 检查select的下拉菜单中选中是否正确
     5 assertSelectedOptions   # 检查下拉菜单中的选项的是否正确
     6 assertText              # 检查指定元素的文本
     7 assertTextPresent       # 检查在当前给用户显示的页面上是否有出现指定的文本
     8 assertTextNotPresent    # 检查在当前给用户显示的页面上是否没有出现指定的文本
     9 assertAttribute         # 检查当前指定元素的属性的值
    10 assertTable             # 检查table里的某个cell中的值
    11 assertEditable          # 检查指定的input是否可以编辑
    12 assertNotEditable       # 检查指定的input是否不可以编辑
    13 assertAlert             # 检查是否有产生带指定message的alert对话框
    14 waitForElementPresent   # 等待检验某元素的存在。为真时,则执行。

    13. 如果有一个按钮,点击该按钮后发出一个ajax call,然后得到返回结果后内容显示到新弹出的一个layer中。在写脚本的时候,点击这个按钮动作是否可以用clickAndWait命令?如果不行,怎么解决?

    不能够。Ajax是一种支持动态改变用户界面元素的技术。在Ajax驱动的应用程序中,数据可以从应用服务器检索,然后显示在页面上,而不需要加载整个页面,只有一小部分页面或者元素本身被重新加载。

    所以不能够使用ClickAndWait,因为Ajax call不会刷新整个页面,clickAndWait命令会因为等待页面重新加载而出现time out。

    也就是说最大的麻烦是判断Ajax调用是否结束。可以用click + pause完成

    使用JQuery进行辅助测试:http://www.cnblogs.com/nbkhic/archive/2011/10/23/2221729.html

    其中,去哪儿网的题目如下:

    一、 UI自动化测试

    Qunar机票搜索场景

    1) 访问Qunar机票首页http://flight.qunar.com,选择“单程”,输入出发、到达城市,选择today+7日后的日期,点“搜索”,跳转到机票单程搜索列表页。

    2) 在列表页停留1分钟,至到页面上出现“搜索结束”。

    3) 如果出现航班列表,对于出现“每段航班均需缴纳税费”的行随机点选“订票”按钮,在展开的列表中会出现“第一程”、 “第二程”;对于没有出现“每段航班均需缴纳税费”的行随机点选“订票”按钮,在展开的列表底部中会出现“报价范围”

    4) 如果不出现航班列表,则页面会出现“该航线当前无可售航班”

    请使用maven创建java工程,引入Selenium框架,编写WebUI代码,实现上述人工操作和验证。要求能随机验证100个城市对的3个月内的任意搜索条件。

     参见答案:http://www.cnblogs.com/tobecrazy/p/4752684.html

    很多人可能第一步就卡住了,怎么选择7天以后的日期呢?

    实际上很简单,直接在输入框里输入就好了。因为selenium支持的语言很多,这里就用js写一下。大家用selenium执行这段js就可以搞定了。

    var date = new Date();
    date.setDate(date.getDate() + 7);
    
    var a_week_later = date.getFullYear() + '-' (date.getMonth()+1) + '-' + date.getDate();
    $('input[name=fromDate]').val(a_week_later);

    参考答案: http://www.cnblogs.com/tobecrazy/p/5873288.html                                     

  • 相关阅读:
    font-weight(字体粗细)属性
    Node.js入门(三)
    js难点问题
    Node.js入门(二)
    Node.js入门(一)
    Reactjs的Controller View模式
    智能社的邀请码
    react native 学习资料汇总
    jquery操作select
    分享
  • 原文地址:https://www.cnblogs.com/lesleysbw/p/5896422.html
Copyright © 2020-2023  润新知