Selenium實戰教程系列(一)--- 瀏覽器操作

Batkid2018發表於2018-10-17

在這個系列的教程中,筆者將根據自己在多年的Selenium自動化測試開發過程中的實戰經驗,為各位朋友進行梳理和總結,提供一個實戰性很強的教程。同時也歡迎各位朋友指出教程的不足之處,一起學習,一起進步。 話不多說,直接進入教程的第一個板塊:瀏覽器操作。

瀏覽器的操作可以說是使用Selenium進行自動化開發中最基礎的內容之一,任何用例的執行都離不開瀏覽器的操作,因為Selenium的原理就是通過程式碼實現對瀏覽器的控制和操作,從而達到模擬人在瀏覽器上執行測試用例的目的。

1.開啟和關閉瀏覽器

開啟瀏覽器

任何的一個測試用例,都需要開啟一個瀏覽器的實體,然後才能進行下面的操作。需要注意的是需要提前安裝好對應瀏覽器的Webdriver。

require 'selenium-webdriver'
# chrome
dr = Selenium::WebDriver.for :chrome
# firefox
dr = Selenium::WebDriver.for :ff
# ie
dr = Selenium::WebDriver.for :ie
複製程式碼

Headless mode

在一些場景下測試工程師需要在不開啟瀏覽器的情況下進行自動化測試,也就是以headless的方式執行自動化測試。 現在全球最受歡迎的瀏覽器Chrome在Chrome 59 (Chrome 60 for Windows)版本中已經支援了headless mode,只需要配置一些簡單的引數就可以實現。

require 'selenium-webdriver'

options = Selenium::WebDriver::Chrome::Options.new
options.add_argument('--headless')
options.add_argument('--disable-gpu')
options.add_argument('--remote-debugging-port=9222')
driver = Selenium::WebDriver.for :chrome, options: options

driver.get "https://www.acitve.com"
driver.save_screenshot("#{File.dirname(__FILE__)}/#{Time.now.strftime("%F")}")
複製程式碼

關閉瀏覽器

執行完操作後,必須保證瀏覽器被關閉。 關閉瀏覽器有兩種方法:

close()

require 'selenium-webdriver'

dr = Selenium::WebDriver.for :chrome
sleep 5
puts '瀏覽器將被關閉'
dr.close()
puts '瀏覽器已經關閉'
複製程式碼

quit()

require 'selenium-webdriver'

dr = Selenium::WebDriver.for :chrome
sleep 5
puts '瀏覽器將被關閉'
dr.quit()
puts '瀏覽器已經關閉'
複製程式碼

兩種方式的區別:

方法 區別
close 關閉當前的瀏覽器視窗
quit 不僅關閉視窗,還會徹底的退出webdriver,釋放與driver server之間的連線

2.設定瀏覽器視窗大小

在執行用例的過程中,可能會需要對視窗的大小進行調整,以滿足測試的要求,因為頁面的佈局在不同的瀏覽器視窗大小下會有不同的展示。 常用的設定主要是:

最大化視窗

require 'selenium-webdriver'

dr = Selenium::WebDriver.for :chrome
dr.maximize_window()
複製程式碼

自定義視窗大小

require 'selenium-webdriver'

dr = Selenium::WebDriver.for :chrome
dr.set_window_size(240, 320)
複製程式碼

通過設定不同的視窗大小,可以在瀏覽器上模擬不同場景的頁面展示,例如設定一個移動端的解析度,就可以看到在移動端的頁面展示是否符合期望。

3.開啟URL

Selenium中有兩種開啟URL的方法:

require 'selenium-webdriver'
dr = Selenium::WebDriver.for :chrome
url = 'http://www.acitve.com'
puts "now access #{url}"
#方法1:
dr.get url

#方法2:
dr.navigate.to url
複製程式碼

這兩種方法的區別在於:

方法 區別1 區別2
get 等待page load完成 無法進行前進後退操作
navigate.to 不會等待page load完成 可以保留瀏覽的歷史,進行前進後退重新整理操作

4.列印當前頁面的title及URL

在驗證當前頁面的標題和URL時時,會需要用到這個功能

require 'selenium-webdriver'

dr = Selenium::WebDriver.for :chrome
url = 'http://www.acitve.com'
dr.get url
puts "The Title of current page is #{dr.title}"
puts "url of current page is #{dr.current_url}"

dr.quit
複製程式碼

5.前進,後退和重新整理

dr.navigate返回的Selenium::WebDriver::Navigation類的物件除了可以進行前面提到的to操作外,還可以進行前進,後退和重新整理。

require 'selenium-webdriver'

dr = Selenium::WebDriver.for :chrome
url1 = 'http://www.acitve.com'
dr.navigate.to url
url2 = 'http://www.acitve.com/contactus'
dr.navigate.to url
puts "url of current page is #{dr.current_url}" #'http://www.acitve.com/contactus'

#返回
dr.navigate.back()
puts "url of current page is #{dr.current_url}" #'http://www.acitve.com'

#前進
dr.navigate.forward()
puts "url of current page is #{dr.current_url}" #'http://www.acitve.com/contactus'

#重新整理
dr.navigate.refresh()
puts "url of current page is #{dr.current_url}" #'http://www.acitve.com/contactus'
複製程式碼

6.設定等待

Selenium中有兩種等待:隱式等待和顯式等待。

  • 隱式等待:設定等待定位介面元素的時間。當等待時間超過設定值後,將丟擲NoSuchElement異常。
# 如果3s內還定位不到則丟擲異常
driver.manage.timeouts.implicit_wait = 3 # seconds
複製程式碼
  • 顯式等待:通過Selenium::WebDriver::Wait物件,設定一個等待的條件,條件成立時繼續執行,超過timeout則丟擲異常。
wait = Selenium::WebDriver::Wait.new(:timeout => 10) # seconds 
wait.until { dr.find_element(class: 'label').displayed? }
複製程式碼

7.切換視窗

在測試過程中有可能會有新視窗開啟,這樣就會有多個視窗同時出現,Selenium提供了方法實現多個視窗間的切換。

  • window_handleSelenium::WebDriver::Driver類的方法,返回當前window的handle。

  • window_handlesSelenium::WebDriver::Driver類的方法,返回全部window的handle陣列。

  • switch_to.window(window_handle)實現跳轉到指定window_handle的視窗

require 'selenium-webdriver'

dr = Selenium::WebDriver.for :chrome
dr.get 'http://the-internet.herokuapp.com/windows'
dr.find_element(css: '.example a').click

windows_array = dr.window_handles
puts "All windows are #{windows_array}"

dr.switch_to.window(windows_array.first)
puts "Current window is #{dr.window_handle}"

dr.switch_to.window(@driver.window_handles.last)
puts "Current window is #{dr.window_handle}"
複製程式碼

8.執行JavaScript

在Selenium自動化測試的開發過程中,很多複雜的控制功能是原生API無法提供或解決的,這就需要用到執行JavaScript來幫助實現。Selenium也提供了介面讓開發者在指令碼中執行JS指令碼。 下面的例子,將演示如何利用JS來實現操作元素的高亮顯示。

# coding: utf-8
require 'selenium-webdriver'

def highlight(element, duration = 3)

  # 保留元素原有的style,以待方法執行完成後恢復
  original_style = element.attribute("style")

  # 給元素加一個紅色的虛線邊界
  $driver.execute_script(
    "arguments[0].setAttribute(arguments[1], arguments[2])",
    element,
    "style",
    "border: 2px solid red; border-style: dashed;")

  # 讓元素的邊界保留一段時間再恢復
  if duration > 0
    sleep duration
    $driver.execute_script(
      "arguments[0].setAttribute(arguments[1], arguments[2])",
      element,
      "style",
      original_style)
  end
end

begin
    $driver = Selenium::WebDriver.for :firefox
    $driver.get 'https://www.jianshu.com'
    highlight $driver.find_element(xpath: "//a[@class='logo']")
ensure
    $driver.quit
end
複製程式碼

利用JS還可以實現很多複雜的功能,筆者將會在後續的教程中專門介紹。

9.處理Cookie

對於Web UI的自動化測試,對於Cookie的處理是比較常見的場景。 Selenium提供了完善的介面讓開發者來對cookie進行處理。

  • 獲取Cookie:獲取全部cookieall_cookies和獲取指定cookie cookie(name)
  • 新增Cookie:add_cookie(name: 'token', value: 'xxxxxx')
  • 刪除Cookie:刪除全部cookie delete_all_cookies 和 刪除指定cookiedelete_cookie(name)
#encoding: utf-8
require 'selenium-webdriver'

dr = Selenium::WebDriver.for :chrome
url = 'http://www.acitve.com'
dr.get url

dr.manage.all_cookies
dr.manage.delete_all_cookies

#通過新增鑑權所需的cookie,可以完成登入的效果
dr.manage.add_cookie(name: 'userid', value: 'xxxxxx')
dr.manage.add_cookie(name: 'token', value: 'xxxxxx')

dr.get url

#刪除一個鑑權需要的cookie後,登入將失效
dr.manage.delete_cookie('token')
dr.get url

dr.quit()
複製程式碼

10.設定代理

在進行UI自動化的過程中,使用代理訪問頁面的場景也是比較常見的,在Selenium中,給瀏覽器設定代理主要是通過對profile的設定實現的。

require 'selenium-webdriver'
PROXY = 'localhost:8087'
profile = Selenium::WebDriver::Firefox::Profile.new
profile.proxy = Selenium::WebDriver::Proxy.new( 
    :http     => PROXY,  
    :ftp      => PROXY,  
    :ssl      => PROXY)
driver = Selenium::WebDriver.for :firefox, :profile => profile
複製程式碼

相關文章