在做web項(xiàng)目時(shí),通常需要開發(fā)一些自動(dòng)化用例,,自動(dòng)化用例執(zhí)行可以設(shè)置觸發(fā)條件,,也可以定時(shí)執(zhí)行,在每次代碼發(fā)生變更的情況下,,自動(dòng)觸發(fā)自動(dòng)化用例執(zhí)行,,可以及時(shí)檢測(cè)修改代碼是否引入新的問題,提高產(chǎn)品的自信度,。在開發(fā)web端自動(dòng)化用例代碼時(shí),,目前大多采用主流的selenium測(cè)試框架,selenium框架中的webdriver驅(qū)動(dòng)瀏覽器模擬人的行為對(duì)頁面進(jìn)行操作,,開發(fā)過程主要可以拆分為以下幾個(gè)階段: a),、web頁面加載 b)、定位頁面元素 c),、操作頁面元素,,主要包括文本框輸入、鼠標(biāo)移動(dòng),、鼠標(biāo)點(diǎn)擊等 d),、判斷返回結(jié)果 其中最主要的就是 b、c 兩步,,首先要定位到對(duì)應(yīng)的元素,,然后才能對(duì)元素進(jìn)行操作。在selenium中提供了8中元素定位方式,,可以通過元素ID號(hào),、標(biāo)簽名稱、元素name屬性,、標(biāo)簽文本內(nèi)容,、cssselector、xpath等方式進(jìn)行定位,,這8中定位方式基本可以滿足所有的元標(biāo)簽元素定位需求,。 但是,在實(shí)際使用中會(huì)發(fā)現(xiàn),,使用如上方式進(jìn)行元素操作經(jīng)常會(huì)遇到如下兩個(gè)問題:
a),、一是代碼執(zhí)行較慢
b)、二是代碼執(zhí)行穩(wěn)定性不高,待操作的元素明明存在,,但可能是由于窗口大小發(fā)生變化導(dǎo)致元素位置發(fā)生變化,,甚至元素重疊的情況,導(dǎo)致代碼報(bào)錯(cuò)“元素不存在”,,或者“元素不在所點(diǎn)擊的位置(點(diǎn)擊操作有可能被另一個(gè)元素所接受)”等莫名其妙的錯(cuò)誤,,降低了自動(dòng)化用例執(zhí)行的穩(wěn)定性。
針對(duì)這種情況,,對(duì)于自動(dòng)化代碼中不穩(wěn)定的部分,,經(jīng)常出錯(cuò)的部分,可以將這部分對(duì)網(wǎng)頁元素進(jìn)行操作的代碼換成對(duì)應(yīng)的JavaScript腳本,,由于瀏覽器原生的支持JavaScript,,JavaScript代碼直接在瀏覽器內(nèi)核中執(zhí)行,就不會(huì)出現(xiàn)元素不在所點(diǎn)擊的位置等錯(cuò)誤,,可以大大提高自動(dòng)化用例執(zhí)行的穩(wěn)定性和執(zhí)行效率,。
下面以使用selenium 調(diào)用JavaScript腳本操作百度主頁進(jìn)行示例演示,首先使用selenium打開Chrome瀏覽器,,加載百度主頁: Created by cheng star at 2018/4/15 13:31 from selenium import webdriver url = 'http://www.baidu.com' driver = webdriver.Chrome() driver.implicitly_wait(10)
百度主頁關(guān)鍵字輸入框和查詢按鈕的HTML結(jié)構(gòu)如下: <span class='bg s_ipt_wr quickdelete-wrap'> <span class='soutu-btn' style='display: block;'/> <input id='kw' class='s_ipt' autocomplete='off' maxlength='255' value='' name='wd'/><!-- 關(guān)鍵字輸入框 --> <a id='quickdelete' class='quickdelete' href='javascript:;' title='清空' style='top: 0px; right: 0px; display: none;'/> <span class='bg s_btn_wr'> <input id='su' class='bg s_btn btnhover' type='submit' value='百度一下'/><!-- 查詢按鈕 -->
1,、輸入關(guān)鍵字并點(diǎn)擊查詢按鈕(方法一) 首先使用DOM對(duì)象的getElementById方法定位元素,然后給value屬性賦值實(shí)現(xiàn)關(guān)鍵字輸入,,然后以同樣的方式獲取查詢按鈕對(duì)象,,并觸發(fā)按鈕的click點(diǎn)擊操作。 var keywordInput = document.getElementById('kw') ; // 根據(jù)全局唯一的ID獲取輸入框?qū)ο?/span> keywordInput.value = 'selenium' ; // 延遲 5 秒點(diǎn)擊查詢按鈕(setTimeout是異步執(zhí)行) var queryBtn = document.getElementById('su') ; // 根據(jù)全局唯一的ID獲取查詢按鈕對(duì)象 driver.execute_script(query)
2,、輸入關(guān)鍵字并點(diǎn)擊查詢按鈕(方法二) 與方法一類似,,首先使用DOM對(duì)象的getElementById方法定位元素,然后給value屬性賦值實(shí)現(xiàn)關(guān)鍵字輸入,,對(duì)于查詢按鈕,,也是以同樣的方式獲取查詢按鈕對(duì)象,但是并不是調(diào)用按鈕對(duì)象的click方法,,而是構(gòu)造一個(gè)event事件對(duì)象,,并將事件對(duì)象綁定在查詢按鈕上實(shí)現(xiàn)按鈕的點(diǎn)擊操作。這樣做是因?yàn)?,有些HTML標(biāo)簽元素沒有onclick屬性,,所以直接調(diào)用click方法并不會(huì)觸發(fā)對(duì)象的點(diǎn)擊操作。
# 方法二(對(duì)于沒有綁定onclick屬性的元素,,click方法無效,可以使用dispatchEvent方法) var keywordInput = document.getElementById('kw') ; // 根據(jù)全局唯一的ID獲取輸入框?qū)ο?/span> keywordInput.value = 'selenium javascript' ; var queryBtn = document.getElementById('su') ; // 根據(jù)全局唯一的ID獲取查詢按鈕對(duì)象 var e = document.createEvent('MouseEvents') ; // 創(chuàng)建事件對(duì)象 e.initEvent('click' , true , true) ; // 初始化事件對(duì)象為 click 事件 queryBtn.dispatchEvent(e) ; driver.execute_script(query)
3,、執(zhí)行JavaScript腳本返回元素對(duì)象 WebElement 使用python調(diào)用selenium框架執(zhí)行JavaScript腳本也可以將JavaScript的執(zhí)行結(jié)果返回給python的一個(gè)對(duì)象,,對(duì)象類型是WebElement,只需要在調(diào)用的JavaScript腳本中使用return 語句返回對(duì)應(yīng)的內(nèi)容即可。
# 執(zhí)行JS腳本返回標(biāo)簽元素對(duì)象 WebElement var keywordInput = document.getElementById('kw') ; keywordInputElement = driver.execute_script(getKeywordInput) keywordInputElement.send_keys('selenium javascript')
4,、執(zhí)行JavaScript腳本在多個(gè)相似元素標(biāo)簽中進(jìn)行過濾,,并操作元素標(biāo)簽(點(diǎn)擊百度主頁的“新聞” 超鏈接) 百度主頁“新聞” 超鏈接對(duì)應(yīng)的HTML結(jié)構(gòu)如下: <a class='mnav' name='tj_trnews' href='http://news.baidu.com'>新聞</a> <a class='mnav' name='tj_trhao123' href='http://www.hao123.com'>hao123</a> <a class='mnav' name='tj_trmap' href='http://map.baidu.com'>地圖</a> <a class='mnav' name='tj_trvideo' href='http://v.baidu.com'>視頻</a> <a class='mnav' name='tj_trtieba' href='http://tieba.baidu.com'>貼吧</a> <a class='mnav' name='tj_trxueshu' href='http://xueshu.baidu.com'>學(xué)術(shù)</a> <a class='lb' οnclick='return false;' name='tj_login' href='https://passport.baidu.com/v2/?login&tpl=mn&u=http%3A%2F%2Fwww.baidu.com%2F&sms=5'>登錄</a> <a class='pf' name='tj_settingicon' href='http://www.baidu.com/gaoji/preferences.html'>設(shè)置</a> <a class='bri' style='display: block;' name='tj_briicon' href='http://www.baidu.com/more/'>更多產(chǎn)品</a>
觀察以上HTML內(nèi)容可以發(fā)現(xiàn),只需要將新聞關(guān)鍵字,,對(duì)所有 a 標(biāo)簽進(jìn)行搜索即可定位新聞超鏈接,,對(duì)應(yīng)的JavaScript代碼如下: var linkParentElement = document.getElementById('u1') ; // 獲取超鏈接的HTML父元素節(jié)點(diǎn) var links = linkParentElement.getElementsByTagName('a') ; // 獲取linkParentElement元素下的所有超鏈接 for(var i = 0 ; i < links.length ; i ) { // 通過 新聞 關(guān)鍵字過濾需要的超鏈接 var linkText = links[i].innerHTML.trim() ; if(linkText.indexOf('新聞') != -1) { links[i].click() ; // 點(diǎn)擊超鏈接 driver.execute_script(clickNewsLink)
5、執(zhí)行JavaScript腳本下拉瀏覽器滾動(dòng)條 var keywordInput = document.getElementById('kw') ; // 根據(jù)全局唯一的ID獲取輸入框?qū)ο?/span> keywordInput.value = 'selenium' ; // 延遲 5 秒點(diǎn)擊查詢按鈕(setTimeout是異步執(zhí)行) var queryBtn = document.getElementById('su') ; // 根據(jù)全局唯一的ID獲取查詢按鈕對(duì)象 // document.documentElement.scrollTop = 10000 ; // 適用于除 Chrome瀏覽器外的其他瀏覽器 document.body.scrollTop = 10000 ; // Chrome瀏覽器使用這種方法 } , 5000) ; // 延遲5 秒下拉滾動(dòng)條到頁面最低端 driver.execute_script(scrollScript)
6,、在頁面眾多相似元素中定位需要操作的元素,,使用多種條件組合過濾 當(dāng)頁面HTML中存在多個(gè)相似的元素標(biāo)簽,很難一次性準(zhǔn)確定位時(shí),,這時(shí)候需要使用一些額外的過濾條件進(jìn)行判斷,,常用的過濾條件包括:hasAttribute判斷元素是否有某一屬性、getAttribute('name') == 'XXX'判斷元素屬性內(nèi)容是否等于XXX,、獲取元素標(biāo)簽內(nèi)容innerHTML并進(jìn)行判斷等,。 如下HTML代碼中包含兩組 a 標(biāo)簽,兩組 a 標(biāo)簽對(duì)外展示的效果相同,,只是當(dāng)點(diǎn)擊第一組鏈接時(shí)會(huì)有alert提示框彈出,,現(xiàn)在需要使用JavaScript腳本點(diǎn)擊第一組 a 標(biāo)簽中的“javascript language'鏈接,并彈出alert提示框,,HTML結(jié)構(gòu)如下: <title>相似標(biāo)簽過濾</title> <a name = 'python' href='javascript:alert('part one - python')'>python language</a><br> <a name = 'java' href='javascript:alert('part one - java')'>java language</a><br> <a name = 'C#' href='javascript:alert('part one - C#')'>C# language</a><br> <a name = 'scala' href='javascript:alert('part one - scala')'>scala language</a><br> <a name = 'javascript' href='javascript:alert('part one - javascript')'>javascript language</a><br> <a href='javascript:alert('part two - python')'>python language</a><br> <a href='javascript:alert('part two - java')'>java language</a><br> <a href='javascript:alert('part two - C#')'>C# language</a><br> <a href='javascript:alert('part two - scala')'>scala language</a><br> <a href='javascript:alert('part two - javascript')'>javascript language</a><br>
對(duì)應(yīng)的JavaScript代碼如下:
var a_tags = document.getElementsByTagName('a') ; // 獲取當(dāng)前頁面的所有 a 標(biāo)簽元素 for(var i = 0 ; i < a_tags.length ; i ) { // 經(jīng)過觀察發(fā)現(xiàn),,要點(diǎn)擊的 javascript 超鏈接有一個(gè) name = 'javascript' 屬性和 關(guān)鍵字javascript var a_text = a_tags[i].innerHTML.trim() ; // 獲取超鏈接的內(nèi)容 if(a_tags[i].hasAttribute('name') && a_text.indexOf('javascript language') != -1) { // 獲取具有屬性 name 且內(nèi)容中包含javascript language 字符串的a標(biāo)簽,并觸發(fā)點(diǎn)擊操作 driver.execute_script(script)
以上分別介紹了在使用selenium自動(dòng)化測(cè)試框架做自動(dòng)化腳本開發(fā)時(shí),,使用JavaScript腳本代碼操作頁面元素的一些常用方法,,其中主要用到了DOM(文檔對(duì)象模型)進(jìn)行元素查找定位,并配合使用元素的hasAttribute,、getAttribute,、innerHTML等屬性方法。
|