面試准備——(三)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\test.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                                     

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM