1. 簡介
本來上一篇就是練習篇的最后一篇文章了,但是有的小伙伴私下反映說是做了那么多練習,沒有一個比較綜合的demo練練手。因此宏哥在這里又補存了一些常見的知識點進行練習,在文章最后也通過實例給小伙伴們或者童鞋們進行了一個登錄模塊的自動化測試的實例,其他的你可以照貓畫虎地輕松的搞定和實現。
2. python-web自動化-三種等待方式
當有元素定位不到時,比如下拉框,彈出框等各種定位不到時;
一般是兩種問題:1 、有frame ;2、沒有加等待
下面學習三種等待方式:
2.1 強制等待 sleep(xx)或者Time.sleep
是在程序運行過程中使用time模塊中的sleep進行代碼的休眠進行強制等待,是顯式等待中的一種極端情況。
這種方法簡單粗暴,不管瀏覽器是否加載完,程序都要等待規定的xx時間,時間到了才繼續執行下面的代碼。
不建議總是用這種等待方式,會嚴重影響程序的執行速度。通過time模塊中sleep進行代碼的暫停,但是實際使用過程中,如果都以sleep進行控制嚴重影響了程序的運行。
2.1.1 參考代碼1
# coding=utf-8🔥 # 1.先設置編碼,utf-8可支持中英文,如上,一般放在第一行 # 2.注釋:包括記錄創建時間,創建人,項目名稱。 ''' Created on 2019-12-10 @author: 北京-宏哥 QQ交流群:705269076 Project: 《手把手教你》系列練習篇之9-python+ selenium自動化測試 ''' # 3.導入模塊 import time # 強制等待——代碼休眠 from selenium import webdriver driver = webdriver.Chrome() driver.get("https://www.baidu.com") time.sleep(3) driver.quit()
2.1.2 參考代碼2
# coding=utf-8🔥 # 1.先設置編碼,utf-8可支持中英文,如上,一般放在第一行 # 2.注釋:包括記錄創建時間,創建人,項目名稱。 ''' Created on 2019-12-10 @author: 北京-宏哥 QQ交流群:705269076 Project: 《手把手教你》系列練習篇之9-python+ selenium自動化測試 ''' # 3.導入模塊 from selenium import webdriver from time import sleep driver = webdriver.Chrome() driver.get('https://www.baidu.com/') sleep(3)#強制性等待3s再執行以下代碼 print(driver.current_url) driver.quit()#退出驅動,關閉所有窗口
2.2 隱性等待 implicitly_wait(xx)
這種方法是設置一個最長的等待時間,如果在規定時間內網頁全部元素加載完成,則執行下一步,否則一直等待時間截止才執行下一步。比強制性等待智能些
!隱性等待對整個driver的周期都起作用,所以只要設置一次即可
2.2.1 參考代碼1
# coding=utf-8🔥
# 1.先設置編碼,utf-8可支持中英文,如上,一般放在第一行
# 2.注釋:包括記錄創建時間,創建人,項目名稱。
'''
Created on 2019-12-10
@author: 北京-宏哥 QQ交流群:705269076
Project: 《手把手教你》系列練習篇之9-python+ selenium自動化測試
'''
# 3.導入模塊
from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException from time import ctime driver = webdriver.Firefox() # 設置隱式等待為10秒 driver.implicitly_wait(10) driver.get("http://www.baidu.com") try: print(ctime()) driver.find_element_by_id("kw22").send_keys('selenium') except NoSuchElementException as e: print(e) finally: print(ctime()) driver.quit()
這里可以看到在10秒內沒有找到想要找到的元素,但是依舊執行了10秒,然后報錯,如果修改代碼為可以找到,代碼執行非常迅速。
implicitly_wait()默認參數的單位為秒,本例中設置等待時長為10秒。首先這10秒並非一個固定的等待時間,它並不影響腳本的執行速度。其次,它並不針對頁面上的某一元素進行等待。當腳本執行到某個元素定位時,如果元素可以定位,則繼續執行;如果元素定位
不到,則它將以輪詢的方式不斷地判斷元素是否被定位到。假設在第6秒定位到了元素則繼續執行,若直到超出設置時長(10秒)還沒有定位到元素,則拋出異常。
2.2.2 參考代碼2
# coding=utf-8🔥 # 1.先設置編碼,utf-8可支持中英文,如上,一般放在第一行 # 2.注釋:包括記錄創建時間,創建人,項目名稱。 ''' Created on 2019-12-10 @author: 北京-宏哥 QQ交流群:705269076 Project: 《手把手教你》系列練習篇之9-python+ selenium自動化測試 ''' # 3.導入模塊 from selenium import webdriver driver = webdriver.Chrome() driver.get('https://www.baidu.com/') driver.implicitly_wait(30)#隱性等待,最長30s print(driver.current_url) driver.quit()
2.3.顯性等待 WebDriverWait
WebDriverWait配合該類的until()和until_not()方法,根據條件靈活的等待
程序每隔xx秒看一眼,如果條件成立了,則執行下一步,否則繼續等待,直到超過設置的最長時間,然后拋出TimeoutException。
顯式等待是你在代碼中定義等待一定條件發生后再進一步執行你的代碼。
A. 使用前,先引用相關庫
B. 確定元素的定位表達式
C. 使用expected_conditions對應的方法來生成判斷條件
WebDriverWait(driver,10,1).until(EC.visibility_of_element_located((By.ID,ele_locator)))
WebDriverWait(driver,10,1).until(EC.visibility_of_element_located((By.XPATH,ele_locator)))
D. 調用WebDriverWait類設置等待總時長、輪詢周期
2.3.1 參考代碼1
# coding=utf-8🔥 # 1.先設置編碼,utf-8可支持中英文,如上,一般放在第一行 # 2.注釋:包括記錄創建時間,創建人,項目名稱。 ''' Created on 2019-12-10 @author: 北京-宏哥 QQ交流群:705269076 Project: 《手把手教你》系列練習篇之9-python+ selenium自動化測試 ''' # 3.導入模塊 #A. 使用前,先引用相關庫 from selenium import webdriver from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By driver = webdriver.Chrome()#打開Chrome瀏覽器 driver.get('https://www.baidu.com/')#打開百度 driver.find_element_by_xpath('//div[@id="u1"]//a[@name="tj_login"]').click()#點擊【登錄】;click() 方法,可模擬在按鈕上的一次鼠標單擊。 # B. 確定元素的定位表達式 ele_locator = "TANGRAM__PSP_10__footerULoginBtn"#通過id,確定‘用戶名登錄’元素 # C. 使用expected_conditions對應的方法來生成判斷條件 # EC.方法名(定位方式,定位表達式) # EC.visibility_of_element_located(By.ID,ele_locator)#元素可見 # D. 調用WebDriverWait類設置等待總時長、輪詢周期 # WebDriverWait(driver, 超時時長, 調用頻率(默認0.5s)).until(可執行方法, 超時時返回的信息) # 等待10秒鍾,每隔1秒去查看對應的元素是否可見;如果可見,繼續下一步操作;如果不可見,則繼續等待,直到10s結束,如果元素還是不可見,則拋出超時異常 WebDriverWait(driver,10,1).until(EC.visibility_of_element_located((By.ID,ele_locator))) driver.find_element_by_id('TANGRAM__PSP_10__footerULoginBtn').click()#點擊【用戶名登錄】 driver.close()#關閉當前窗口
2.3.2 參考代碼2
# coding=utf-8🔥
# 1.先設置編碼,utf-8可支持中英文,如上,一般放在第一行
# 2.注釋:包括記錄創建時間,創建人,項目名稱。
'''
Created on 2019-12-10
@author: 北京-宏哥 QQ交流群:705269076
Project: 《手把手教你》系列練習篇之9-python+ selenium自動化測試
'''
# 3.導入模塊
from time import ctime
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 dr = webdriver.Chrome() dr.get('https://www.baidu.com') try: print(ctime()) element = WebDriverWait(dr, 10).until( EC.presence_of_element_located((By.ID, "kw")) ) # WebDriverWait(driver=self.driver, timeout=300, poll_frequency=0.5, ignored_exceptions=None) # driver:瀏覽器驅動 # timeout:最長超時等待時間 # poll_frequency:檢測的時間間隔,默認為500ms # ignore_exception:超時后拋出的異常信息,默認情況下拋 NoSuchElementException 異常 print("我已找到") finally: print(ctime()) dr.quit()
執行結果:
以上代碼執行后就發現,整段代碼執行速度非常快,即使我在WebDriverWait中設置10秒,也不會等待10秒的情況,因為在不到一秒內,已經完成了加載並定位id為“kw”的元素。
通過WebDriverWait 和 ExpectedCondition 組合使用,讓我們的代碼執行只需要等待需要的時長,而不是固定的時長,這樣最大限度的節省時間。
此外ExpectedCondition類中提供了很多預期條件判斷方法,省去了再創建包的功夫:
""" title_is:判斷當前頁面的title是否等於預期 title_contains:判斷當前頁面的title是否包含預期字符串 presence_of_element_located:判斷某個元素是否被加到了dom樹里,並不代表該元素一定可見 visibility_of_element_located:判斷某個元素是否可見. 可見代表元素非隱藏,並且元素的寬和高都不等於0 visibility_of:跟上面的方法做一樣的事情,只是上面的方法要傳入locator,這個方法直接傳定位到的element就好了 presence_of_all_elements_located:判斷是否至少有1個元素存在於dom樹中。舉個例子,如果頁面上有n個元素的class都是'column-md-3',那么只要有1個元素存在,這個方法就返回True text_to_be_present_in_element:判斷某個元素中的text是否 包含 了預期的字符串 text_to_be_present_in_element_value:判斷某個元素中的value屬性是否包含了預期的字符串 frame_to_be_available_and_switch_to_it:判斷該frame是否可以switch進去,如果可以的話,返回True並且switch進去,否則返回False invisibility_of_element_located:判斷某個元素中是否不存在於dom樹或不可見 element_to_be_clickable - it is Displayed and Enabled:判斷某個元素中是否可見並且是enable的,這樣的話才叫clickable staleness_of:等某個元素從dom樹中移除,注意,這個方法也是返回True或False element_to_be_selected:判斷某個元素是否被選中了,一般用在下拉列表 element_located_to_be_selected element_selection_state_to_be:判斷某個元素的選中狀態是否符合預期 element_located_selection_state_to_be:跟上面的方法作用一樣,只是上面的方法傳入定位到的element,而這個方法傳入locator alert_is_present:判斷頁面上是否存在alert """
另外這里使用了until()函數也可以使用until_not()
until_not(method, message='')
調用該方法體提供的回調函數作為一個參數,直到返回值為False
until(method, message='')
調用該方法體提供的回調函數作為一個參數,直到返回值為True
3. 下拉框or彈框
通常情況下,在網頁中會有一些下拉框進行選擇或者給你一個彈框告訴你需要進行確認,遇到這樣的情況如何解決呢,宏哥在這里就來簡單地說一說……‘’
3.1 代碼實現:
3.2 參考代碼:
# coding=utf-8🔥 # 1.先設置編碼,utf-8可支持中英文,如上,一般放在第一行 # 2.注釋:包括記錄創建時間,創建人,項目名稱。 ''' Created on 2019-12-09 @author: 北京-宏哥 QQ交流群:705269076 Project: python+ selenium自動化測試練習篇8 ''' # 3.導入模塊 import time from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.support.select import Select driver = webdriver.Chrome() driver.get("https://www.baidu.com") time.sleep(5) # driver.find_element(By.ID, "kw").send_keys("selenium&python") # driver.find_element(By.ID, "su").click() # driver.find_element(By.XPATH, '/html/body/div[1]/div[5]/div[1]/div[2]/div[1]/div[2]/div[1]').click() # driver.find_element(By.XPATH, '/html/body/div[1]/div[5]/div[1]/div[2]/div[1]/div[1]/span[2]').click() # 折騰半天才發現定位出來的不是下拉框…… driver.find_element(By.LINK_TEXT, '設置').click() driver.find_element(By.LINK_TEXT, '搜索設置').click() time.sleep(2) sel = driver.find_element(By.XPATH, '//*[@id="nr"]') # 定位下拉框 Select(sel).select_by_value('50') # 通過value的值進行選定條目 driver.find_element(By.CLASS_NAME, 'prefpanelgo').click() time.sleep(2) driver.switch_to.alert.accept() # 此處同意警告框提示內容 time.sleep(2) driver.quit()
3.3 運行結果:
運行代碼后,控制台打印如下圖的結果
3.4 瀏覽器
瀏覽器跳轉到設置頁面,會提示“已記錄下您的偏好”
在百度首頁想要進行設置每次搜索頁面顯示的數目,就會有一個下拉框進行選擇,這里可以導入Select這個模塊進行對下拉框進行選擇,通常下拉框的列表是包含一個值的,這樣就可以通過value來選定,完成設置之后,當然是要保存設置啦,點擊保存發現,居然有
一個彈框,這可如何是好,切換至alert之后接受吧……
通過在編輯器中的提示,我們同樣可以給彈框發送一個值,當然這里設置中並沒有出現這類情況。
這次對下拉框和彈框的處理過程中,折騰了不短時間,原因就是元素等待的問題,下回要仔細研究下元素等待的問題了。
4. 自動化測試demo
使用selenium進行測試,當然是需要進行驗證的,此時結合python的斷言函數就變得非常有用了。測試中設定好預期,當實際情況與預期有差別,給出錯誤信息,好像正是所希望的。
來一段簡單的代碼看下斷言的基本使用:
# coding:utf-8 import time from selenium import webdriver dr = webdriver.Chrome() dr.maximize_window() dr.get("https://www.baidu.com") print(dr.title) try: assert (dr.title == "百度,你就知道") except: print('標題錯誤,請查看錯誤信息') time.sleep(5) dr.quit()
獲取頁面的title是否符合我們的預期,當打開的網頁title不是我們想要的,不僅從函數assert的提示信息看到原因,也可輸出簡單的提示信息。
Web登錄測試是很常見的測試,手動測試大家再熟悉不過了,那如何進行自動化登錄測試呢!本文就基於python+selenium結合unittest單元測試框架來進行一次簡單但比較完整的cnblog自動化登錄測試,可提供點參考!下面就包括測試代碼和每種測試情況的截圖。
另一種方式是結合python測試框架unittest進行驗證。以下的代碼只是為了演示:
# coding=utf-8🔥 # 1.先設置編碼,utf-8可支持中英文,如上,一般放在第一行 # 2.注釋:包括記錄創建時間,創建人,項目名稱。 ''' Created on 2019-12-10 @author: 北京-宏哥 QQ交流群:705269076 Project: python+ selenium自動化測試練習篇9 ''' # 3.導入模塊 import unittest from selenium import webdriver from time import sleep ''' cnblog的登錄測試,分下面幾種情況: (1)用戶名、密碼正確 (2)用戶名正確、密碼不正確 (3)用戶名正確、密碼為空 (4)用戶名錯誤、密碼正確 (5)用戶名為空、密碼正確(還有用戶名和密碼均為空時與此情況是一樣的,這里就不單獨測試了) ''' class LoginCase(unittest.TestCase): def setUp(self): self.dr = webdriver.Chrome() self.dr.maximize_window() # 定義登錄方法 def login(self, username, password): self.dr.get('https://passport.cnblogs.com/user/signin') # cnblog登錄頁面 self.dr.find_element_by_id('LoginName').send_keys(username) self.dr.find_element_by_id('Password').send_keys(password) self.dr.find_element_by_id('submitBtn').click() def test_login_success(self): '''用戶名、密碼正確''' self.login('北京-宏哥', '!qaz2wsx') # 正確用戶名和密碼 sleep(3) link = self.dr.find_element_by_id('lnk_current_user') self.assertTrue('北京-宏哥' in link.text) # 用assertTrue(x)方法來斷言 bool(x) is True 登錄成功后用戶昵稱在lnk_current_user里 self.dr.get_screenshot_as_file("D:\\cnblogtest\\login_success.jpg") # 截圖 可自定義截圖后的保存位置和圖片命名 def test_login_pwd_error(self): '''用戶名正確、密碼不正確''' self.login('北京-宏哥', 'kemi') # 正確用戶名,錯誤密碼 sleep(2) error_message = self.dr.find_element_by_class_name('ajax-error-box').text self.assertIn('用戶名或密碼錯誤', error_message) # 用assertIn(a,b)方法來斷言 a in b '用戶名或密碼錯誤'在error_message里 self.dr.get_screenshot_as_file("D:\\cnblogtest\\login_pwd_error.jpg") def test_login_pwd_null(self): '''用戶名正確、密碼為空''' self.login('北京-宏哥', '') # 密碼為空 error_message = self.dr.find_element_by_id('Password-error').text self.assertEqual(error_message, '請輸入密碼') # 用assertEqual(a,b)方法來斷言 a == b 請輸入密碼等於error_message self.dr.get_screenshot_as_file("D:\\cnblogtest\\login_pwd_null.jpg") def test_login_user_error(self): '''用戶名錯誤、密碼正確''' self.login('北京-宏哥1', '!qaz2wsx') # 密碼正確,用戶名錯誤 sleep(2) error_message = self.dr.find_element_by_id('ajax-error-box').text self.assertIn('用戶名或密碼錯誤', error_message) # 用assertIn(a,b)方法來斷言 a in b self.dr.get_screenshot_as_file("D:\\cnblogtest\\login_user_error.jpg") def test_login_user_null(self): '''用戶名為空、密碼正確''' self.login('', '!qaz2wsx') # 用戶名為空,密碼正確 error_message = self.dr.find_element_by_id('LoginName-error').text self.assertEqual(error_message, '請輸入登錄用戶名') # 用assertEqual(a,b)方法來斷言 a == b self.dr.get_screenshot_as_file("D:\\cnblogtest\\login_user_null.jpg") def tearDown(self): sleep(2) print('自動測試完畢!') self.dr.quit() if __name__ == '__main__': unittest.main()
通過以上代碼,我們可以看到使用selenium和unittest框架結合,已經可以對用戶登陸的模塊做一個簡單的自動化測試。
但是現在博客園的登陸機制的改變有可能部分用例不成功,但是你知道怎么做就可以了。
測試截圖如下:
正確用戶名和密碼登錄成功!
用戶名正確,密碼為空
用戶名為空,密碼正確
5. 小結
好了,今天的分享就到這里吧!!!謝謝各位的耐心閱讀。
您的肯定就是我進步的動力。如果你感覺還不錯,就請鼓勵一下吧!記得點波 推薦 不要忘記哦!!!