天天看點

Selenium自動化測試

一、認識Selenium

  • Selenium架構
    Selenium自動化測試
  • Selenium核心元件

    1.selenium webdriver client

    2.selenium drivers

    3.selenium IDE

    4.selenium grid

    需要同一時間在多個浏覽器和作業系統上進行測試時;

    要節省測試套件的執行時間時。

二、搭建測試環境

安裝Chrome

檢視Chrome的版本,需要安裝适合版本的Chromedriver。

Selenium自動化測試

安裝Chromedriver

  • 第三⽅浏覽器驅動下載下傳

    ​​https://www.seleniumhq.org/download/​​

    ​​https://npm.taobao.org/mirrors/chromedriver​​

  • 找到與本機電腦Chrome版本最接近Chromedriver版本
    Selenium自動化測試
    Selenium自動化測試
  • 解壓并把chromedriver複制到chrome安裝目錄下
    Selenium自動化測試
  • chromedriver添加PATH環境變量
    Selenium自動化測試
  • 檢視chromedriver版本
    Selenium自動化測試

ps:設定環境變量後如果沒有生效,嘗試重新開機電腦。

安裝Selenium的IDE

ps:安裝需要梯子。

IDE是入門的好工具。

Selenium自動化測試
Selenium自動化測試
Selenium自動化測試

安裝selenium庫

Pychram安裝selenium庫,建立項目,做為client。

Selenium自動化測試
Selenium自動化測試

三、IDE錄制腳本

  • 錄制腳本
    Selenium自動化測試
    Selenium自動化測試
    Selenium自動化測試
    Selenium自動化測試
    Selenium自動化測試
    Selenium自動化測試
    Selenium自動化測試
    Selenium自動化測試
    Selenium自動化測試
    Selenium自動化測試
  • 分析定位符

    先執行錄制的腳本,在此基礎上,可以分析定位符。

    Selenium自動化測試
    Selenium自動化測試
    在頁面上點選“社團”
    Selenium自動化測試

回到ide,發現有css定位表達式

Selenium自動化測試

四、編寫用例

  • 導入依賴

    ​​

    ​from selenium import webdriver​

  • 初始化driver

    ​​

    ​driver = webdriver.Chrome()​

    ​​

    ​driver = webdriver.Firefox()​

    ​​

    ​driver = webdriver.Ie()​

    ​​

    ​driver = webdriver.Edge()​

    ​​

    ​driver = webdriver.Opera()​

  • 具體步驟
  • 斷言assert
  • 退出

五、 WebDriver對象操作(API)

對WebDriver對象的操作可以抽象成你怎麼去控制浏覽器,主要方法有:

1.通路URL

​driver.get("https://www.baidu.com/")​

2.視窗大小調整

  • 設定寬800px 高600px

    ​​

    ​driver.set_window_size(800,600) ​

  • 設定最大,最小

    ​​

    ​driver.maximize_window()​

    ​​

    ​driver.minimize_window()​

3.重新整理頁面

​driver.refresh()​

4.前進後退

​driver.forward()​

​driver.back()​

5.關閉浏覽器或視窗

  • 關閉浏覽器

    ​​

    ​driver.quit()​

  • 關閉視窗

    ​​

    ​driver.close()​

    有多個視窗的時候,隻會關閉目前視窗。

6.傳回目前的一些屬性

  • 傳回目前url

    ​​

    ​driver.current_url​

  • 傳回目前視窗句柄

    ​​

    ​driver.current_window_handle​

  • 傳回所有視窗句柄

    ​​

    ​driver.window_handles​

# 在新浪登入頁面點選注冊,在注冊頁面郵箱位址輸入框中輸入郵箱位址,再次跳轉到登入頁面。
from selenium import webdriver
import time
 
driver = webdriver.Chrome()
driver.maximize_window()
driver.get('http://mail.sina.com.cn/')
#擷取目前視窗句柄
now_handle = driver.current_window_handle
time.sleep(1)
#點選注冊連結
driver.find_element_by_link_text('注冊').click()
time.sleep(1)
#擷取所有視窗句柄
handles  = driver.window_handles
#對所有視窗句柄循環處理
for handle in handles:
    if handle != now_handle:
        #視窗變化之後需要定位目前視窗
        driver.switch_to.window(handle)
        time.sleep(2)
        driver.find_element_by_name('email').send_keys('bing')
        time.sleep(2)
        #關閉注冊頁面
        driver.close()
driver.switch_to.window(now_handle)
time.sleep(2)
#在賬号輸入框輸入郵箱
driver.find_element_by_id('freename').send_keys('bing')
time.sleep(2)
 
driver.quit()      
  • 傳回title

    ​​

    ​driver.title​

  • 擷取目前頁面代碼

    ​​

    ​driver.page_source​

    ​​

    7.查找元素,傳回Element對象

    ​driver.find_element_by_css_selector()​

    ​​

    ​driver.find_element_by_name()​

    ​​

    ​driver.find_element_by_id()​

    ​​

    ​driver.find_element_by_tag_name()​

    ​​

    ​driver.find_element_by_class_name()​

    ​​

    ​driver.find_element_by_link_text()​

    ​​

    ​driver.find_element_by_partial_link_text()​

    ​​

    ​driver.find_element_by_xpath()​

8.切換視窗

​driver.switch_to_window(handle)​

9.切換frame

切換架構,直接輸入iframe的name或id屬性,或者傳入定位的元素

​driver.switch_to_frame(frame_reference)​

10.截圖保持為檔案

​driver.get_screenshot_as_file(img_path_name)​

img_path_name為檔案路徑,隻支援.png格式,檔案名注意帶上字尾,如“/Screenshots/foo.png”

11.執行js

  • 簡單執行

    ​​

    ​driver.execute_script(script, *args)​

    ​​

    script:要執行的JavaScript。

    *args:JavaScript的所有适用參數。

  • 異步執行

    ​​

    ​driver.execute_async_script(script, *args)​

12.操作cookie

  • 擷取cookie

    ​​

    ​driver.get_cookies()​

  • 添加cookie

    ​​

    ​driver.add_cookie(cookie_dict)​

  • 删除全部cookie

    ​​

    ​driver.delete_all_cookies()​

  • 删除一個指定cookie

    ​​

    ​driver.delete_cookie(name)​

六、元素定位

  • 元素定位本質上分為三大類
    Selenium自動化測試
  • 使用Chrome驗證元素定位表達式

    右鍵點選“檢查”

    Selenium自動化測試
    檢視HTML
    Selenium自動化測試

進入Console驗證定位表達式

輸入​

​$()​

​可以驗證css定位

輸入​

​$x()​

​可以驗證xpath定位

Selenium自動化測試
  • 元素定位常見錯誤

    1.element is not attached to the page document

    ​selenium.common.exceptions.StaleElementReferenceException: Message: stale element reference: element is not attached to the page document​

    2.NoSuchElementException

  • 元素定位思路

    1.直接定位,有id、name,優先使用這兩個定位,不行再嘗試class、屬性、标簽定位。

    2.相對定位,就是根據層級關系定位。層級定位,先找到全局層級,再找下面的層級。

CSS定位

1.CSS常用屬性定位

css可以通過元素的id、class、标簽這三個正常屬性直接定位元素。

# 百度搜尋框HTML如下:
<input type="text" class="s_ipt" name="wd" id="kw" maxlength="100" autocomplete="off">      
  • css用#号表示id屬性
# chrome中驗證定位表達式:$('#kw')
driver.find_element(By.CSS_SELECTOR,'#kw')
driver.find_element_by_css_selector('#kw')      
  • css用.表示class屬性
# chrome中驗證定位表達式:$('.s_ipt')
driver.find_element(By.CSS_SELECTOR,'.s_ipt')
driver.find_element_by_css_selector('.s_ipt')      
  • css直接用标簽名稱,無任何标示符

    ​​

    ​$('input')​

  • Selenium自動化測試

2.CSS其它屬性定位

css除了可以通過标簽、class、id這三個正常屬性定位外,也可以通過其它屬性定位。

通過其他屬性定位,得把屬性放在方括号裡。

Selenium自動化測試
# chrome中驗證定位表達式:$('[type="text"]')
driver.find_element(By.CSS_SELECTOR,'[type="text"]')
driver.find_element_by_css_selector('[type="text"]')      

3.通過标簽與屬性的組合來定位元素

  • 标簽+class屬性定位
# chrome中驗證定位表達式:$('input.s_ipt')
driver.find_element(By.CSS_SELECTOR,'input.s_ipt')
driver.find_element_by_css_selector('input.s_ipt')      
  • 标簽+id屬性定位
# chrome中驗證定位表達式:$('input#kw')
driver.find_element(By.CSS_SELECTOR,'input#kw')
driver.find_element_by_css_selector('input#kw')      
  • 标簽+其他屬性定位
# chrome中驗證定位表達式:$('input[type="text"]')
driver.find_element(By.CSS_SELECTOR,'input[type="text"]')
driver.find_element_by_css_selector('input[type="text"]')      
Selenium自動化測試

看這裡都是把标簽放在前面,如果開始不是标簽可以嗎?把标簽放在屬性後面呢?

4.CSS層級關系定位

元素不能直接定位的時候,才考慮使用層級關系定位。

觀察HTML的結構,一層一層找到包含要定位元素的父元素、父父元素,然後一層一層定位。

層級可以跳躍嗎?

​div>p:選擇父元素為 <div> 元素的所有 <p> 元素。​

​$('form>span>[type="text"]')​

Selenium自動化測試

5.CSS索引定位

​p:nth-child(2):選擇屬于其父元素的第二個子元素的每個 <p> 元素。​

input:nth-child(2) :選擇屬于 input 父元素的第2個子元素的每個 input 元 素

Selenium自動化測試

定位頁面如下:

Selenium自動化測試
Selenium自動化測試

定位id為menu的父元素下标簽為li的元素

Selenium自動化測試
Selenium自動化測試
Selenium自動化測試
Selenium自動化測試

練習位址:​​https://www.w3school.com.cn//cssref/css_selectors.asp​​

Selenium自動化測試

​$('.govsite-top>a:nth-child(2)')​

Selenium自動化測試

6.CSS邏輯運算定位

css同樣也可以實作邏輯運算,同時比對兩個屬性,但跟xpath不一樣,無需寫and關鍵字。

​$('input[type="text"][autocomplete="off"]')​

Selenium自動化測試

​$('[type="text"][autocomplete="off"]')​

Selenium自動化測試

​$('.s_ipt[type="text"][autocomplete="off"]')​

Selenium自動化測試
Selenium自動化測試

XPATH定位

1.xpath概念相關

xpath是什麼?XML路徑語言。用來在HTML/XML文檔中查找資訊的語言。

xpath使用路徑表達式來擷取節點/節點集,和正常電腦檔案路徑類似。

絕對路徑 / :/從根節點開始;

相對路徑//://相對路徑(推薦用),相對于整個源碼查找。

Selenium自動化測試
Selenium自動化測試
Selenium自動化測試
Selenium自動化測試

2.xpath定位方式(路徑表達式+索引+屬性)

  • 利用标簽内的屬性進行定位

    (1)通過id屬性(标簽+id)

    ​$x('//input[@id="Popover1-toggle"]')​

    Selenium自動化測試
    Selenium自動化測試

    (2)通過name屬性定位

    小結:xpath = "//标簽名[@屬性='屬性值']"

    屬性判斷條件:最常見為id,name,class等等,屬性的類别沒有特殊限制,隻要能夠唯一辨別一個元素即可。

    當某個屬性不足以唯一差別某一個元素時,也可以采取多個條件組合的方式,如下:

    ​xpath= "//input[@type='XX' and @name='XX']"​

    ​$x('//input[@class="Input" and @type="text"]')​

    Selenium自動化測試
  • 利用text()方法定位

    ​$x('//div[text()="草稿箱"]')​

    Selenium自動化測試
    Selenium自動化測試
  • 利用contains()方法定位,也叫模糊定位

    ​xpath = "//标簽名[contains(@屬性, '屬性值')]"​

    Selenium自動化測試
    Selenium自動化測試
  • 利用相對空間定位

    如果一個元素無法通過自身屬性直接定位到,則可以先定位它的父(或父的父,它爺爺)元素,然後再找下一級即可。

    例如要定位如下元素:

    Selenium自動化測試
    首先定位到“阿裡巴巴”
    Selenium自動化測試
    看到“阿裡巴巴”要往上4層才與定位的元素在同一父類元素下
    Selenium自動化測試
    Selenium自動化測試
    Selenium自動化測試

    ​$x('//table[@class="search__stock__bd"]//span[text()="阿裡巴巴"]/../../../..//i[@class="iconfont"]')​

    Selenium自動化測試
  • 邏輯定位

    ​//*[@text="交易" and contains(@resuorce-id,'current_price')]​

其他定位

通過id屬性定位

driver.find_element_by_id(‘loginForm’) 
#定位<form id="loginForm">

#簡單寫法,導入By子產品
from selenium.webdriver.common.by import By 
driver.find_element(By.ID,"loginForm")      

通過name屬性定位

driver.find_element_by_name(‘username’) 
#定位<input name="username" type="text" />
driver.find_element(By.NAME,"username")      

通過class名定位

driver.find_element_by_class_name(‘content’) 
#定位<p class="content">Site content goes here.</p>
driver.find_element(By.CLASS_NAME,"content")      

通過TagName标簽名定位

driver.find_element_by_tag_name(‘input’) 
#定位<input name="username" type="text" />,如果比對了多個,預設隻選第一個
driver.find_element(By.TAG_NAME,"input")      

通過link text定位,就是通過a标簽的text内容定位

driver.find_element_by_link_text(‘Continue’)  #全比對
driver.find_element_by_partial_link_text(‘Con’) #部分比對
#定位<a href="continue.html">Continue</a>
driver.find_element(By.LINK_TEXT,‘Continue’)
driver.find_element(By.PARTIAL_LINK_TEXT,‘Con’)      

元素Element事件

元素定位是傳回元素,需要對元素進行操作才可以實作自動化測試。

Element對象有一系列的方法,可以操作定位的元素。

1.Element.click() 點選元素

​driver.find_elements_by_link_text(‘Continue’).click()​

2.輸入文本

# 有些輸入框中原有的文本不會被自動清除掉,需要使用clear()方法清除 driver.find_element_by_name(‘username’).clear() 
# 輸入内容 driver.find_element_by_name(‘username’).send_keys("username")      

3.擷取參數

# 擷取對應特性值 
Element.get_attribute(name) 
# 擷取對應屬性值 
Element.get_property(name) 
# property是DOM中的屬性,是JavaScript裡的對象;attribute是HTML标簽上的特性,它的值隻能夠是字元串。一般用 attr就行 
# 擷取目前元素的内容 
Element.text 
# 擷取目前元素标簽名 
Element.tag_name 
# 擷取目前元素尺寸 
Element.size 
# 擷取目前元素坐标 
Element.location      

4.判斷方法

#判斷目前元素是否可見 
Element.is_displayed() 
#判斷目前元素是否被啟用 
Element.is_enabled() 
#判斷目前元素是否被選中 
Element.is_selected()      

等待

現在的網頁,基本都是使用ajax異步的加載各種資源的,是以可能我們需要定位的元素不會第一時間就加載出 來,這時候是無法定位的,也就會抛出異常。而解決這個問題的方法,就是等待。

定時等待

不推薦使用定時等待,在正式腳本中很少使用,可在調試腳本的時候使用。

import time 
time.sleep(10)      

隐式等待

一種全局的設定,設定一個最大時長,如果定位的元素沒有出現就會循環查找元素直到逾時或者元素出現,相比于定時等待,這個更加彈性,元素出現了就不會等待了。

from time import sleep
from selenium import webdriver  # driver需要的依賴
from selenium.webdriver.common.by import By  # 元素定位

class TestBiying:
    # 做初始化的操作
    def setup_method(self):
        # 執行個體化webdriver對象
        self.driver = webdriver.Chrome() 
        # 打開url
        self.driver.get('https://baidu.com/')  
        # 隐式等待
        self.driver.implicitly_wait(5)      

顯式等待

顯式等待就是設定一個條件,同時設定一個時間,在這個時間範圍内,如果網頁出現符合的條件的元素,就不等待繼續執行,如果沒有則循環查找元素直到逾時報錯。

from selenium import webdriver from selenium.webdriver.common.by import By 
from selenium.webdriver.support.ui import WebDriverWait 
from selenium.webdriver.support import expected_conditions as EC 
 
driver = webdriver.Firefox()
driver.get("http://somedomain/url_that_delay_loading") 
try:     
  element=WebDriverWait(driver,10).until(EC.presence_of_element_located((By.ID,"myDynamicElement"))) 
finally:     
  driver.quit()      

這段代碼主要講的是:

  1. 執行個體化WebDriverWait類,傳入driver與最大等待時長10秒 ,預設poll_frequency(掃描頻率)為0.5秒。
  2. until()是WebDriverWait類的一個方法,參數是一個等待條件(expected_conditions),如果滿足等待條件,則WebDriverWait類停止等待,并且傳回expected_conditions的值,否則當等待時間到将抛出 TimeoutException異常。
  3. WebDriverWait類還有個方法until_not(),如果不滿足等待條件,就停止等待。
  4. 等待條件(expected_conditions)如果成功則傳回element對象,或有些是傳回布爾值,或者其它不為 null的值。
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait

class TestMail():
    def setup(self):
        self.driver = webdriver.Chrome()
   
    def test_window(self):
        self.driver.get('https://testerhome.com/topics/21805')
        self.driver.implicitly_wait(5)
        self.driver.find_element_by_link_text('第六屆中國網際網路測試開發大會').click()
        # 列印視窗,可以觀察到出現了多個視窗
        print(self.driver.window_handles)
        # 切換視窗
        self.driver.switch_to.window(self.driver.window_handles[1])
        ele = (By.LINK_TEXT,'演講申請')
        WebDriverWait(self.driver,10).until(EC.element_to_be_clickable(ele))
        self.driver.find_element(*ele ).click()      

等待條件(expected_conditions)内置的方法主要有:

  • title_is : #驗證 driver 的 title 是否與傳入的 title 一緻,傳回布爾值。
  • title_contains : #驗證 driver 的 title 中是否包含傳入的 title,傳回布爾值。
  • presence_of_element_located :# 驗證頁面中是否存在傳入的元素,傳入元素的格式是 locator 元組,如 (By.ID, "id1"),傳回element對象。
  • visibility_of_element_located : #驗證頁面中傳入的元素( locator 元組格式 )是否可見,這裡的可見不僅僅是 display 屬性非 None ,還意味着寬高均大于0,傳回element對象或false。
  • visibility_of : #驗證頁面中傳入的元素( WebElement 格式 )是否可見。傳回element對象或false。
  • presence_of_all_elements_located : #驗證頁面中是否存在傳入的所有元素,傳入元素的格式是 locator 元組構成 的 list,如 [(By.ID, "id1"), (By.NAME, "name1"),傳回element或false。
  • text_to_be_present_in_element : #驗證在指定頁面元素的text中是否包含傳入的文本,傳回布爾值。
  • text_to_be_present_in_element_value : #驗證在指定頁面元素的value中是否包含傳入的文本,傳回布爾值。
  • frame_to_be_available_and_switch_to_it : #驗證frame是否可切入,傳入 locator 元組 或 WebElement,傳回布爾值。
  • invisibility_of_element_located : #驗證頁面中傳入的元素( locator 元組格式 )是否可見,傳回布爾值。
  • element_to_be_clickable : #驗證頁面中傳入的元素( WebElement 格式 )是否點選,傳回element。
  • staleness_of : #判斷傳入元素(WebElement 格式)是否仍在DOM中,傳回布爾值。
  • element_to_be_selected : #判斷傳入元素(WebElement 格式)是否被選中,傳回布爾值。
  • element_located_to_be_selected :# 判斷傳入元素(locator 元組格式)是否被選中,傳回布爾值。
  • element_selection_state_to_be :# 驗證傳入的可選擇元素(WebElement 格式)是否處于某傳入狀态,傳回布爾值。
  • element_located_selection_state_to_be : #驗證傳入的可選擇元素(WebElement 格式)是否處于某傳入狀态,傳回布爾值。
  • alert_is_present : #驗證是否有 alert 出現,傳回alert對象。

一般使用:檢查元素是否存在、檢查元素是否可見、檢查元素是否可點選。

1.presence_of_element_located :# 驗證頁面中是否存在傳入的元素,傳入元素的格式是 locator 元組,如 (By.ID, "id1"),傳回element對象 。2.visibility_of_element_located : #驗證頁面中傳入的元素( locator 元組格式 )是否可見,這裡的可見不僅僅是 display 屬性非 None ,還意味着寬高均大于0,傳回element對象或false。

3.visibility_of : #驗證頁面中傳入的元素( WebElement 格式 )是否可見。傳回element對象或false。

4.invisibility_of_element_located : #驗證頁面中傳入的元素( locator 元組格式 )是否可見,傳回布爾值。

5.element_to_be_clickable : #驗證頁面中傳入的元素( WebElement 格式 )是否點選,傳回element。

ps:具體的差別不是很明白。

ps:傳入格式?

元素狀态大概這樣區分

title出現

dom出現 presence

css出現 visibility

js執行 clickable

應用場景

隐式等待盡量預設都加上,時間限定在3-6s,不要太長,這是為了所有的findElemen方法都有一個很好的緩沖。

顯式等待用來處理隐式等待無法解決的一些問題,比如檔案上傳。

定時等待一般不推薦,除非特殊情況。

Action Chains類模拟滑鼠行為

ActionChains簡介

Actionchains是selenium裡面專門處理滑鼠相關的操作如:滑鼠移動,滑鼠按鈕操作,按鍵和上下文菜單(滑鼠右鍵)互動。

這對于做更複雜的動作非常有用,比如懸停和拖放。

Actionchains也可以和快捷鍵結合起來使用,如ctrl,shif,alt結合滑鼠一起使用。

當你使用actionchains對象方法,行為事件是存儲在actionchains對象隊列。當你使用perform(),事件按順序執行。

方法一:可以寫一長串

menu = driver.find_element_by_css_selector(".nav")
hidden_submenu = driver.find_element_by_css_selector(".nav #submenu1")
ActionChains(driver).move_to_element(menu).click(hidden_submenu).perform()      

方法二:可以分幾步寫

menu = driver.find_element_by_css_selector(".nav")
hidden_submenu = driver.find_element_by_css_selector(".nav #submenu1")
actions = ActionChains(driver)
actions.move_to_element(menu)
actions.click(hidden_submenu)
actions.perform()      

使用Actionchains首先需要執行個體化,然後調用其中的方法,完成相應的操作。

import time
from selenium import webdriver
from selenium.webdriver import ActionChains

browser =webdriver.Firefox()
browser.get('http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable')
# 切換frame,id = 'iframeResult'
browser.switch_to.frame('iframeResult')                         
# 被拖拽的對象
source = browser.find_element_by_css_selector('#draggable')     
# 目标對象
target = browser.find_element_by_css_selector('#droppable')     
actions = ActionChains(browser)
actions.drag_and_drop(source, target)
actions.perform()
time.sleep(3)
browser.close()      

常見的滑鼠操作

click(on_element=None)

滑鼠單擊

click_and_hold(on_element=None)

滑鼠單擊并且按住不放

context_click(on_element=None)

右擊

double_click(on_element=None)

輕按兩下

drag_and_drop(source, target)

拖拽

drag_and_drop_by_offset(source, xoffset, yoffset)

将目标拖動到指定的位置

key_down(value, element=None)

按住某個鍵,使用這個方法可以友善的實作某些快捷鍵,比如下面按下Ctrl+c鍵

​ActionsChains(browser).key_down(Keys.CONTROL).send_keys('c').perform()​

key_up(value, element=None)

松開某個鍵,可以配合上面的方法實作按下Ctrl+c并且釋放。

​ActionsChains(browser).key_down(Keys.CONTROL).send_keys('c').key_up(Keys.CONTROL).perform()​

move_by_offset(xoffset, yoffset)

指定滑鼠移動到某一個位置,需要給出兩個坐标位置

move_to_element(to_element)

将滑鼠移動到指定的某個元素的位置

move_to_element_with_offset(to_element, xoffset, yoffset)

移動滑鼠到某個元素位置的偏移位置

perform()

将之前的一系列的ActionChains執行

release(on_element=None)

釋放按下的滑鼠

send_keys(*keys_to_send)

向某個元素位置輸入值

send_keys_to_element(element, *keys_to_send)

向指定的元素輸入資料

Frames與多窗⼝處理

官方把selenium.webdriver包中的switch方法全部封裝成了witch_to包。

switch_to包的方法詳解

Selenium自動化測試
  • driver.switch_to.parent_frame()

    是switch_to中獨有的方法,可以切換到上一層的frame,對于層層嵌套的frame很有用。

    switch_to.frame

    Selenium自動化測試

    switch_to.window

    例如,通路https://testerhome.com/topics/21805,點選“第六屆中國網際網路測試開發大會”,會彈出一個新的視窗,然後在新的視窗再點選“演講申請”。

    Selenium自動化測試
    Selenium自動化測試
    Selenium自動化測試
def test_window(self):
    self.driver.get('https://testerhome.com/topics/21805')
    self.driver.implicitly_wait(5)
    self.driver.find_element_by_link_text('第六屆中國網際網路測試開發大會').click()
    print(self.driver.window_handles)
    self.driver.switch_to.window(self.driver.window_handles[1])
    ele = (By.LINK_TEXT,'演講申請')
    WebDriverWait(self.driver,10).until(EC.element_to_be_clickable(ele))
    self.driver.find_element(*ele ).click()      
Selenium自動化測試

複用浏覽器

通過設定Chrome options參數來複用浏覽器。

Chrome Options是一個配置chrome啟動時屬性的類,通過這個參數我們可以為Chrome添加參數,以實作一些功能,如設定預設編碼、設定代理、設定無頭模式等。

首先打開一個調試的浏覽器,需要在環境變量中PATH裡将chrome的路徑添加進去。

​chrome --remote-debugging-port=9222​

Selenium自動化測試
from time import sleep
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait

class TestHome():
    def setup(self):
        chromeOptions = Options()
        #9222是端口号,隻要是不被占用的端口号都可以
        chromeOptions.add_experimental_option('debuggerAddress', '127.0.0.1:9222')
        # 使用webdriver,需要from selenium import webdriver
        self.driver = webdriver.Chrome(options=chromeOptions)
        # 隐式等待,是全局生效的
        self.driver.implicitly_wait(3)      
Selenium自動化測試

執行個體化webdriver下的ChromeOptions

設定浏覽器的調試位址

複用浏覽器

這兩種形式的差別?

cookie處理

如何擷取cookie?

執行JavaScript

在打開一個網頁的時候,可以執行JS擷取一些資料,特别是性能資料。

一般隻會用到execute_script,源代碼如下:

def execute_script(self, script, *args):
  """
   Synchronously Executes JavaScript in the current window/frame.
  
   :Args:
    - script: The JavaScript to execute.
    - \*args: Any applicable arguments for your JavaScript.
  
   :Usage:
       driver.execute_script('return document.title;')
   """
   converted_args = list(args)
   command = None
   if self.w3c:
       command = Command.W3C_EXECUTE_SCRIPT
   else:
       command = Command.EXECUTE_SCRIPT
  
   return self.execute(command, {
       'script': script,
       'args': converted_args})['value']      

在Chrome中也可以執行JS,可以先在Chrome中驗證,再copy到腳本中。

Selenium自動化測試

如打開網站,擷取性能資料。

Selenium自動化測試
def test_JS(self):
    for code in [
      # 擷取網頁标題
      'return document.title',
      # 擷取性能資料
      'return JSON.stringify(performance.timing)',
    ]:
      result = self.driver.execute_script(code)
      print(result)      

結果如下:

Selenium自動化測試

多浏覽器測試

通過參數傳入浏覽器,使用指令行執行腳本。

無UI執行測試用例

1.phantomJS

這個項目已經沒有維護了。

2.chrome的headless模式

通過設定Chrome options參數

options.add_argument('--headless')

檔案上傳和下載下傳

PO

PO是什麼

PageObject,顧名思義,頁面對象。

PO适用于UI自動化測試。

Selenium自動化測試

2013年馬丁·福勒提出PageObject思想

​​https://martinfowler.com/bliki/PageObject.html​​

selenium引入PO

​​https://github.com/SeleniumHQ/selenium/wiki/PageObjects​​

為什麼需要使用PO

在做UI自動化測試的時候,讓人很頭疼的一個問題是頁面元素經常變化,這時候測試用例也得跟着改變。為了讓測試用例保持穩定,可以把元素定位、元素操作與測試用例進行分離。把元素定位、元素操作具體操作細節封裝成一個方法,測試用例直接調用這個方法,編寫測試用例的時候就無需關注操作細節。在業務流程沒有變化的情況下,頁面元素發生了變化,那隻需要對封裝方法進行修改,測試用例可以保持不變。

友善分工與合作

友善從業務角度了解測試用例

Selenium自動化測試

PO的原則

  • ⽅法意義

    ❖ ⽤公共⽅法代表UI所提供的功能

    ❖ ⽅法應該傳回其他的PageObject或者傳回⽤于斷⾔的資料

    ❖ 同樣的⾏為不同的結果可以模組化為不同的⽅法

    ❖ 不要在⽅法内加斷⾔

  • 字段意義

    ❖ 不要暴露頁⾯内部的元素給外部

    ❖ 不需要模組化UI内的所有元素

如何使用PO

首頁

Selenium自動化測試

注冊頁

Selenium自動化測試

登入頁

BasePage聲明driver的類型為WebDriver,不然繼承BasePage後不能自動帶出driver的方法。

Selenium自動化測試
Selenium自動化測試
Selenium自動化測試
Selenium自動化測試
Selenium自動化測試

參數化

Selenium自動化測試遇到的問題

  • [Pycharm] AttributeError: module 'selenium.webdriver' has no attribute 'Firefox'

    ​​https://www.jianshu.com/p/2409c638665a​​

    重新建立一個虛拟環境,建立一個項目

  • element is not attached to the page document
  • NoSuchElementException
    Selenium自動化測試

常見控件

單選框、複選框、下拉框、表格