Appium python自動化測試系列之元素的定位(六)

來源:互聯網
上載者:User

標籤:變化   編譯   context   根據   bre   www   重要   androi   依次   

?6.1 常用定位方法講解

對象定位是自動化測試中很關鍵的一步,也可以說是最關鍵的一步,畢竟你對象都沒定位那麼你想操作也不行。所以本章節的知識我希望大家多動手去操作,不要僅僅只是書本上的知識,畢竟這個我只能夠舉例說明。下面我們來看我們常用的一些定位方式。

6.1.1 ID定位

無論是在web自動化還是app自動化中id都是唯一的,可能有的小夥伴看到這裡會有疑問,因為有的資料說是通過name定位是唯一的,為什麼你這裡是id呢,其實這個在之前是不衝突的,但是如果你用的是appium較新版本是不行的,在新版本中name定位被去掉了,所以在以後的定位中不會有name定位了,通常情況下我們也更喜歡用id進行定位。這裡可能剛學的小夥伴會有疑問,有的時候你的應用為什麼沒有id,或者說在這個手機上有但是另外的手機上沒有。1、開發沒有添加。2、android版本是4.4以下的。

我們直接看下面這張圖片

上面圖片中左邊部分用紅色圈出來的對象的id我們在右邊的屬性中可以看到,他的id我同樣是用紅色圈出,如果我們需要對“手機號/郵箱”這個輸入框進行輸入資訊,我們只需操作右邊的id就行,下面我們直接看代碼。

driver.find_element_by_id("cn.com.open.mooc:id/account_edit").send_keys("111111")

  

通過上面的代碼我們能夠直接在使用者資訊輸入框中輸入使用者資訊111111。可能對於無基礎的人來說這裡會又點兒迷糊,這個driver是哪裡來的,driver在我們配置啟動的時就已經初始化,我們只需要調用他的方法find_element_by_id。如果你的ide有自動補全功能,那麼你在輸入後面的方法時會發現一個問題,為什麼還有一個find_elements_by_id呢?這個在後面我們會講解,下來可以思考一下。

6.1.2 className定位

在實際工作中className定位用得相對而言會比較少。當你經常去看class時你會發現很多的className是一樣的,你沒有辦法對其進行唯一定位,下面我們看下面兩張圖片

我們可以仔細看一下這兩張圖片中手機號、密碼兩個輸入框中的className都是一樣的,如果在這種情況下你使用

driver.find_element_by_class_name("android.widget.EditText").send_keys("111111")

  

這種方式去定位,你會發現你永遠定位不了密碼欄,這是為什麼呢?因為在設計的時候如果你尋找的元素在頁面有多個,系統會自動給你選擇第一個,所以你永遠操作不了後面的,那如何解決這種問題呢?我們看後面講解。

6.1.3 xpath定位

xpath定位在web自動化中是最常見的,而且也是最有效,使用xpath定位避免了找不到元素導致報錯的問題,但是在app中使用xpath定位是一件很low的事情。為什麼這麼說呢?因為在作者的經曆中只要遇見使用xpath定位元素他的反應就會比較慢,自動化的目的是為了提高效率,但是使用xpath後會降低效率,所以這裡說很 low。但很多時候我們不得不去瞭解,下面我們大概講解一下。首先我們要熟悉一下web的xpath定位。

講web的xpath之前大家先裝一下fireFox瀏覽器,再在瀏覽器中安裝fireBug以及FirePath兩個外掛程式。如:

在自動化或者學習xpath時這兩個外掛程式是必不可少的,這裡我們直接講xpath,我們來看下面一張圖片理解一下

用紅色圈出有虛線的輸入框我們看一下xFirePath給我們的定位,在定位的xpath中顯示的是“.//*[@id=‘kw‘]”,這個是什麼意思呢?我們來一步一步講解。1、//*  選取文檔中的所有元素 。2、@id=‘kw‘]  匹配屬性為id且值為kw的節點。這裡有的小夥伴可能不是很理解,說這裡直接使用id進行定位就行。其實也是,但是當沒有這個屬性的時候呢?我們看下面這張圖片

name定位無效的情況下,當你看到這張圖片的時候如果你不用xpath怎麼定位呢?有一些抓狂的感覺吧。小夥伴可以嘗試著自己使用xpath進行定位,可能有一些人發現xpath中定位不是很明白了,為什麼呢?.//*[@id=‘u1‘]/a[4]  在這個xpath中我們沒有像之前那樣思路清晰了他多了一些層級關係,這個後面我們會仔細講。這個xpath中首先第一步1、@id=‘u1‘和之前的一樣匹配屬性為id值為ul的節點,然後再在他的下面進行定位2、/a[4]  意思就是從根節點下選取第四個a元素。這樣一步一步解析是否更加容易理解了呢?下面我們看一下在xpath定位中經常用到的一些文法,下來大家多多練習。

這個是我們經常用到的,而且是最基礎的知識,只有這些沒有辦法完成很多古怪的需求,那麼就有更難的,下面我們看下面的列表

上面這些知識都是在http://www.w3school.com.cn/xpath/xpath_examples.asp 裡面,大家下來後一定要多看,多練習。

下面我們直接看在app中xpath的使用

在上面兩張圖片中我們能夠清除的看見他們的id、className都是一樣的,這樣的情況下不用層級定位方式我們只能夠採用xpath來進行定位,首先根據前面web的學習大家可以思考一下該怎麼定位。我們直接看代碼

driver.find_element_by_xpath("//android.widget.TextView[@text=‘JavaScript‘]").click()

  

在xpath裡面我們的文法是這樣“//android.widget.TextView[@text=‘JavaScript‘]”,這個和我們之前web的xpath一樣,意思是尋找所有節點中節點為android.widget.TextView (這裡使用的是className,也可以使用id,系統會依次去找)並且他的text屬性值為JavaScript,這樣是否更容易理解呢?下來多練習。這樣的定位方式不推薦,效率很慢。

6.2 層級定位6.2.1 什麼是層級定位

在前面的章節中我們已經提到了層級定位,只是不知道具體怎麼操作而已。在很多的自動化中如果只是靠簡單的定位是沒有辦法完成自動化的,就像剛xpath定位一樣,有的元素的id、name、className都是一樣的,xpath定位效率低下,這個時候我們大多數都會採用層級定位。

6.2.2 項目中層級定位如何運用

下面我們舉一個簡單的例子來理解層級定位。

從上面的圖片我們可以看出id為cn.com.open.mooc:id/rv_child的節點下麵包含了很多的android.widget.FrameLayout

從這張圖片我們不難看出,如果我們要定位這個元素我們是沒辦法去定位的,這種情況我們大多數使用的是層級定位以及xpath,這裡我們來看如何使用層級定位。

首先我們可以看出兩幅圖的結構上的區別,第二幅圖元素他是在第一幅圖裡面的,這裡我們稱第一幅圖id為cn.com.open.mooc:id/rv_child的節點為第二幅圖元素的父節點,我們只需要先通過id定位到父節點,然後再從父節點往下面進行定位就好。現在你可以練習一下,看和我的結果一樣嗎?看代碼:

 

element = driver.find_element_by_id("cn.com.open.mooc:id/rv_child")element.find_element_by_class_name("android.widget.FrameLayout").click

  

按照思維我們的代碼會是上面的結果,但是你去運行會發現不報錯,可也不會點擊,這個是為什麼呢?我們看下面的圖片

在父節點下的所有子節點他的className都是“android.widget.FrameLayout”,這種情況下他怎麼去點擊操作呢?所以在這種情況下會引發一個新的定位問題,就是我們接下來要講的List定位。

6.3 List定位

List故名思義就是一個列表,在python裡面也有list這一個說法,如果你不是很理解什麼是list,這裡暫且理解為一個數組或者說一個集合。首先一個list是一個集合,那麼他的個數也就成了不確定性,所以這裡需要用複數,所以在我們定位時我們不能夠接著用find_element_by_id等等定位方式了,我們需要用他的複數形式find_elements_by_id,所有的定位方式都一樣需要採用複數加s。這裡我們接著上面的案例講,如何使用list定位想定位的元素。首先看一片:

我們查看圖片可以知道我們能夠很輕鬆的通過id定位到整個父節點,我們接下來需要做的事定位這個父節點下所有的“android.widget.RelativeLayout”節點,同樣的首先我們看一張圖:

這裡我們需要直接使用定位複數的方法來操作,直接看代碼:

element = driver.find_element_by_id("cn.com.open.mooc:id/rv_child")  elements = element.find_elements_by_class_name("android.widget.RelativeLayout")

  

通過上面的代碼我們直接定位了cn.com.open.mooc:id/rv_child 父節點下的所有android.widget.RelativeLayout子節點,現在我們需要怎麼去操作這個子節點了,這裡有兩種方法:

1、前面我們講了List你可以理解為一個數組或者一個集合,這裡定位的所有子節點最後就成了個list,如果我們要訪問這個list裡面的某一個元素我們可以像訪問數組中的資料一樣通過下標訪問。最後的代碼就是下面這個樣子:

element = driver.find_element_by_id("cn.com.open.mooc:id/rv_child")elements = element.find_elements_by_class_name("android.widget.RelativeLayout")elements[1].click();

  

上面的代碼最後的結果是選擇了JavaScript這個標籤頁面,然後點擊進入。

備忘:如果初學者不理解是如何通過下標訪問的,這裡說一下下標是從0開始,如果要訪問list i中的第一個元素結果就是i[0],這部分知識會在後面python基礎中會講到。

2、如果你要訪問List裡面的元素,那麼我們是否可以通過for迴圈語句來依次訪問呢?這個在自動化中會經常用到。下面你可以通過這個思路自己去實戰一下,看能否達到預期效果。下面看My Code:

element = driver.find_element_by_id("cn.com.open.mooc:id/rv_child")elements = element.find_elements_by_class_name("android.widget.RelativeLayout")for ele in elements:  ele.click()

  

看上面的代碼,我們通過迴圈去訪問這個list裡面的每一個元素,因為每次迴圈得到的都是其中一個元素,那麼我們只需要在這個元素上加上你想要的操作即可,所以我們這裡可以直接點擊進去。

如果你動手做到這裡會發現一個問題,你進入到第一個標籤後沒一會兒系統就會報錯,為什麼呢?你也可以試著去解決這個問題,後面我們會講解這塊兒知識。

6.4 內嵌H5定位6.4.1 hybrid定位思考

在web自動化中我們會遇見frame的問題,在遇見這些內嵌的標籤後我們需要做的就是切換視窗,那麼在app自動化測試也有類似的情況就是我們經常看見的內嵌html,在我們原生的app中增加一個由html做成的頁面。大家可以思考一下這種情況怎麼操作。

6.4.2 hybrid常見定位問題分析

首先我們看一下下面一張圖片:

通過右邊的結構圖我們能夠清晰的看見整個頁面就是一個webview,無論從什麼角度來定位我們都不能夠很好的進行,如果這個時候我們需要操作頁面的元素就需要通過切換contexts來完成。但是在講這個知識點之前大家先按照網上的知識來試一下處理這個頁面,看能否成功。下面先說大家會遇見的問題:

1、可能你看到有的文章顯示我們不需要通過切換contexts就能夠完成定位,這樣的情況有,但是那種情況作者只在微博登入、qq登入等第三方登入時遇見過,如果不是這樣的情況而像上面的情況就沒辦法通過類似的方法進行完成,所以我希望讀者遇見這種情況時自己動手去操作,看什麼方式更加適合自己的項目。

2、需要切換contexts那麼就需要擷取頁面的所有contexts,此時你通過官網或者其他文章的知識通過下面的方法來擷取,可能會報錯,這種情況關係不大。

webview = self.driver.contextsprint webview

  

如果你通過上面的代碼來調試但是卻報錯,但是其他資料卻沒問題時你也不要著急,這裡你需要確定兩件事情:(1)、app打包的時候需要開啟webview 的debug屬性setWebContentDebuggingEnabled(true),這個直接讓開發加上就好。一般情況是開啟的,畢竟他們也要調試。(2)、你用很多手機去調試,發現有一些可以有一些不可以,但是你用模擬器卻都可以,根據官方給出的答案是這個時候你需要去將手機root,然後再試。目前作者遇見了這兩種情況,第二種我也是調試了很久才找到原因。

6.4.3 hybrid定位講解

這兩個問題解決後那麼定位webview就輕鬆搞定,直接看代碼:

webview = driver.contextsdriver.switch_to.context(webview[1])driver.find_element_by_link_text(‘PHP‘).click()

  

對於初學者對於上面的代碼可能不是很理解,下面我們看一下日誌:

大家這裡不用管我執行代碼和之前的區別(多了一個self),我們看下面控制台的輸出,輸出的是一個list,前面說過list和數組類似,在這個list裡面有兩個元素“NATIVE_APP”,“WEBVIEW_cn_com_open_mooc”,第一個元素是我們原生的app的contexts,後面的則是我們的webview的context,所以我們需要擷取webview的context時只需要通過這個list的下表來進行訪問。

我們擷取到webview的context後只需要通過driver.switch_to.context()進行切換就好。當切換後我們就可以像定位web一樣進行定位。

看下面一張圖片我們通過瀏覽器將h5頁面開啟:

通過上面的圖片我們就能夠很輕鬆的像web一樣進行定位,也就可以使用web的一些定位方式。看到這裡是不是覺得解決了一個難題呢?動手去吧。

6.4.4 hybrid問題實戰

通過前面的學習我相信你已經有了一些實戰能力,這裡給大家提一個問題,我們擷取到的contexts每次一定是兩個嗎?如果不是兩個那麼我們上面的指令碼是不是就沒辦法用了呢?可以思考一下這裡怎麼解決,在看我們下面的思路以及解決方案。

無論在什麼頁面我們去擷取contexts時他無論有幾個但是他的類型是不是肯定都是一個list呢?既然是list那麼我們是否可以取到裡面的每一個值,然後把每一個值進行判斷,只要找出我們的webview就可以了呢?下面看代碼:

#擷取當前頁面所有的contextswebview = driver.contexts#在擷取到的contexts list裡面去挨個迴圈for context in webview:    #判斷迴圈中單個的context是否是webview,如果是就進行切換,並且跳出迴圈  if ‘WEBVIEW‘ in context:    driver.switch_to.context(context)    breakdriver.find_element_by_link_text(‘PHP‘).click()

  

通過上面的代碼我們是否完美的解決了內嵌H5的定位問題呢?動手吧

6.5 滑動定位6.5.1 滑動定位方式

在app自動化中我們經常會遇見一個問題,我們需要尋找的元素不在當前可展示的螢幕,至於在什麼地方我們不知道,如果這個時候我們一直使用在當前頁面尋找,那麼系統就會報錯,為瞭解決這個問題我們就需要使用滑動尋找。

首先的思路是我們在需要尋找對象的頁面尋找一下該元素,判斷該元素是否在當前頁面,如果該元素不在該頁面那麼我們就需要去互動螢幕,到我們的下一螢幕,然後再進行尋找,依次類推到找到為止。

6.5.2 滑動定位思路分析

方式我們有了,那麼我們就需要知道實現這個功能應該有哪些點。下面跟著我一起來分析一下:

1、需要尋找的元素我們是不是需要知道是什麼呢?這個需要先確定

2、我們需要找的頁面是在我們的當前頁面的上方還是下方還是左方還是右方,我們不能確定,那麼我們是否需要確定我們需要滑動的方向?

3、元素和方向有了,但是你知道我們每次需要滑動螢幕的多少嗎?那麼我們是否需要先去擷取螢幕的大小,然後針對不同的方向去計算一個滑動的值呢?

萬事具備只欠東風,去按照這個思路動手練習一吧。

6.5.3 滑動定位實戰

一、根據上面的思路我們能首先來確定我們需要尋找的元素,看下面圖片:

我們要找實戰推薦後面的“換一換”按鈕,然後進行點擊。首先我們查看他的定位資訊

最後我們尋找元素的定位資訊代碼如下:

self.driver.find_element_by_id(‘cn.com.open.mooc:id/tv_replace‘).click()

  對於有一定基礎的人可能會覺得這個很low,但是有沒有思考過一個問題,我們可以通過這個代碼去執行,在沒有這按鈕的時候卻會報錯,也就沒有辦法執行下去了,那麼需要怎麼處理呢?所以這個時候我們需要有一些python的容錯知識,即使我們的代碼執行出錯了,那麼也要讓他按照我們的意思執行下去。try.......except.......,這個就是我們python中的容錯處理 ,下面我們看添加後的代碼:

try:self.driver.find_element_by_id(‘cn.com.open.mooc:id/tv_replace‘).click()except Exception,e:print e

  

try的意思就是告訴編譯器試著去執行他下面這一段代碼,如果報錯了,那麼你就把except裡面的錯誤資訊列印出來。

二、有了元素現在我們需要知道的是不是就是該怎麼滑動介面了呢?首先我們看一下下面這張圖片:

在我們使用app的過程中存在上面幾種滑動情況,我們把整個介面看作為一個座標系(x,y),如果我們需要往上滑動,那麼我們是不是就是x軸不動,y軸從下往上動呢?往下就是x軸不動,y軸從上往下呢?同理左右滑動是不是就是應該y軸不動x軸左右滑動呢?可以好好去體會一下,腦海中有個畫面。

在appium中滑動我們所需要使用的方法就是swipe函數,至於往哪個方向滑動就是看我們裡面的x,y的值,如果我們需要下往上滑動那麼我們就應該是:

 

self.driver.swipe(x1,y1,x1,y2,t)

  

上面的代碼x軸的值不變,y軸的值進行了變化,所以是沿著上下進行滑動的,從y2滑動到了y1點。t代表的是多少時間完成這個動作,或者說這個時間持續多久。

備忘:這裡需要注意的是螢幕的x,y的值是從左上方開始取的,左上方為(0,0),右下角是最大。

三、上面滑動的方法看著是好用,但是我們不可能每次都去填寫一個座標,那樣太low,所以我們需要擷取螢幕大小,直接看代碼:

x = self.driver.get_window_size()[‘width‘]y = self.driver.get_window_size()[‘height‘]

  上面的代碼就是我們擷取到的x,y軸。通過思路我們的代碼都有了,下面我們要做的就是對原來的代碼進行修改,進行一個封裝。下面看代碼,這個暫時看不懂沒關係,到後面我們學了python‘基礎就能夠看懂了。先思路,然後瞭解。

#擷取螢幕大小        def getSize(self):  x = self.driver.get_window_size()[‘width‘]  y = self.driver.get_window_size()[‘height‘]  return (x,y)                #向左滑動def swipeLeft(self,t):  l=self.getSize()  x1=int(l[0]*0.9)  y1=int(l[1]*0.5)  x2=int(l[0]*0.1)  self.driver.swipe(x1,y1,x2,y1,t)              #向右滑動def swipeRight(self,t):  l=self.getSize()  x1=int(l[0]*0.25)  y1=int(l[1]*0.5)  x2=int(l[0]*0.75)  self.driver.swipe(x1,y1,x2,y1,t)              #向上滑動def swipeUp(self,t):  l=self.getSize()  x1=int(l[0]*0.5)  y1=int(l[1]*0.8)  y2=int(l[1]*0.4)  self.driver.swipe(x1,y1,x1,y2,t)  time.sleep(5)        #向下滑動def swipeDown(self,t):  l=self.getSize()  x1=int(l[0]*0.5)  y1=int(l[1]*0.25)  y2=int(l[1]*0.75)  self.driver.swipe(x1,y1,x1,y2,t)        #尋找元素,沒找到滑動def findLocal(self):  x = 1  while x==1:    if self.fact() == 1:      self.swipeUp(2000)      time.sleep(3)      self.fact()    else:      print "找到了"      x=2                            #遞迴def fact(self):  n =1  try:    self.driver.find_element_by_id(‘cn.com.open.mooc:id/tv_replace‘).click()  except Exception,e:    return n

  通過查看上面代碼的整個邏輯就是1、首先去尋找元素,如果找到了我就直接點擊。2、如果沒有找到元素那麼我就往上滑動(這裡可以自己選擇),滑動後再次進行尋找,如果找到就點擊,沒有找到繼續滑動。動手動手,這裡知識點很重要!雖然後面會有一些替代方法,但是思路、演算法很重要。

 

 

Appium python自動化測試系列之元素的定位(六)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.