篇11?????? python自動(dòng)化測(cè)試應(yīng)用-python調(diào)用安卓adb命令(下篇)
--lamecho辣么丑
1.1概要
大家好!我是lamecho(辣么丑),今天是《python自動(dòng)化測(cè)試應(yīng)用》的第十一篇,本篇將繼續(xù)第十篇的adb命令結(jié)合pyapp框架編寫過程中實(shí)際遇到的那些坑婚瓜。后面的內(nèi)容不是簡(jiǎn)單的列舉命令(因?yàn)榫W(wǎng)絡(luò)上大把,大家關(guān)心什么可以自己搜索),而是一貫lamecho辣么丑的風(fēng)格呕童,實(shí)戰(zhàn)。好了各位同學(xué)坐穩(wěn)了淆珊,我要發(fā)車了夺饲,哈哈。
1.2?那些需要注意的adb命令
1.2.1?“adb?shell input ……”
這條命令施符,在測(cè)試過程中也是經(jīng)常用到的往声,它后面可以跟tap,text戳吝,swipe浩销,進(jìn)行點(diǎn)擊屏幕,輸入文本听哭,滑屏的操作慢洋,具體在python中使用按照命令格式執(zhí)行也不會(huì)出現(xiàn)什么問題。但是如果我們要長(zhǎng)按某個(gè)元素欢唾,從而實(shí)現(xiàn)具體功能呢且警?下面給出實(shí)現(xiàn)代碼。
def long_press(dev,data,hold_time):
????action='adb -s '+dev+' shell input touchscreen swipe '+'%d'%data[0][0]+' '+'%d'%(data[0][1])+' '+'%d'%data[-1][0]+' '+'%d'%(data[-1][1])+' '+hold_time
????print action
????pi= subprocess.Popen(action,shell=True,stdout=subprocess.PIPE)
long_press('4d0041b1be98b01f',[[540,716],[545,718]],'1000')
可以看到我定義的long_press方法礁遣,action里用到的仍然是swipe命令斑芜,大家知道swipe是滑動(dòng)屏幕的操作,那么如果我們?cè)趥鬟f滑動(dòng)范圍坐標(biāo)的時(shí)候祟霍,設(shè)定的滑動(dòng)范圍非常小杏头,那么是不是就是間接的達(dá)到了長(zhǎng)按某一個(gè)區(qū)域的目的盈包,然后配合一個(gè)整個(gè)命令的執(zhí)行時(shí)間的參數(shù),是不是就完美解決了長(zhǎng)按這個(gè)動(dòng)作醇王。
我們看一看完整的adb命令:
adb -s 4d0041b1be98b01f shell input touchscreen swipe 540 716 545 718 1000
解釋:-s?后跟設(shè)備號(hào)呢燥,swipe?先傳移動(dòng)坐標(biāo)范圍“540 716 545 718”,然后1000是長(zhǎng)按的時(shí)間寓娩,1000的單位是毫秒(注意)叛氨。
大家不要以為這條命令就這樣介紹結(jié)束了,還沒有棘伴。按道理來(lái)說(shuō)input后面的source源在swipe命令里默認(rèn)就是touchscreen寞埠,所以一般我們?cè)趯戇@條命令時(shí)是可以省略touchscreen的,但是實(shí)際我在編寫pyapp框架的時(shí)候(由于pyapp設(shè)計(jì)需要支持多臺(tái)設(shè)備)焊夸,拿了不同型號(hào)品牌(分辨率)的手機(jī)做適配仁连,畢竟框架要照顧的范圍要必須廣要有一定的普適性。我發(fā)現(xiàn)阱穗,在pyapp的僚機(jī)模式下(就是一臺(tái)主設(shè)備操控多臺(tái)附屬設(shè)備歡迎關(guān)入群”631466916“饭冬,獲取最新pyswat和pyapp程序),主設(shè)備的長(zhǎng)按操作在有些副設(shè)備上實(shí)現(xiàn)不成功揪阶,開始我也是在命令里省略了touchscreen昌抠。開始也想不到什么原因,因?yàn)槊顏?lái)說(shuō)也不復(fù)雜不存在寫錯(cuò)的情況鲁僚,畢竟有些副設(shè)備還是能正確響應(yīng)動(dòng)作的扰魂,后來(lái)我把shell?input命令的幫助結(jié)果打印出來(lái)研究了一下(見上一篇文中有截圖),在swipe命令的參數(shù)傳遞中說(shuō)明了touchscreen是缺省蕴茴,默認(rèn)屬性,所以正常來(lái)說(shuō)我們是不用在命令中明確指定該參數(shù)值的姐直,然而我也是瞎貓碰到死耗子倦淀,試著在命令里加入了touchscreen,最后執(zhí)行結(jié)果每一臺(tái)副設(shè)備在長(zhǎng)按命令的執(zhí)行上都成功了声畏。
1.2.2?adb命令如何輸入中文撞叽?
adb命令里進(jìn)行輸入文本輸入‘a(chǎn)db -s 設(shè)備號(hào)shell input text 輸入的內(nèi)容’。在原生的adb命令里是不支持中文輸入的插龄,所以我們?cè)跍y(cè)試的時(shí)候只能輸入英文字符愿棋。然而實(shí)際我們?cè)谧鯽pp測(cè)試的時(shí)候避免不了需要輸入中文字符的情況,這里給大家介紹一種曲線救國(guó)的辦法均牢。利用“ADBKeyBoard”輸入法來(lái)進(jìn)行中文的輸入糠雨,通過廣播的方式達(dá)到輸入中文字符,具體命令:adb?shell?am broadcast -a ADB_INPUT_TEXT --es msg “內(nèi)容”徘跪。
1.2.3?啟動(dòng)應(yīng)用
在appium的應(yīng)用中每次只能開啟一個(gè)app甘邀,而如果用adb命令的話就靈活許多琅攘,輸入:adb?shell?am start –n package名/.activity名,這里的package名和activity名和appium中配置的一致。比如我們啟動(dòng)計(jì)算器程序松邪,對(duì)應(yīng)的命令就是“adb shell am start -n com.android.calculator2/.Calculator”坞琴。這里要再提醒大家一點(diǎn),APP的package名和activity名一定要找對(duì)特別是activity名逗抑,具體的找發(fā)大家可以參看我的《python自動(dòng)化測(cè)試應(yīng)用-第2篇(APP測(cè)試)--Appium初識(shí)篇》里邊講解了具體的查找方法剧辐。當(dāng)然大家也是可以根據(jù)adb命令去進(jìn)行查找,在pyapp測(cè)試框架中我就是根據(jù)adb命令進(jìn)行名稱的查找啟動(dòng)應(yīng)用的邮府。這里我講解一下思路荧关,利用命令adb shell pm list packages -3,將手機(jī)中安裝的第三方app列舉出來(lái)挟纱,然后通過時(shí)間比對(duì)找到新安裝的app從而確定名稱羞酗。其實(shí)大家只要有了思路可以在百度中查找對(duì)應(yīng)的命令即可。
1.2.4 只會(huì)發(fā)短信紊服,那么查看短信呢檀轨?不會(huì)你就out了!
網(wǎng)上你可能找到如何發(fā)短信欺嗤,打電話的相關(guān)adb命令的介紹参萄,其實(shí)原理也就是1.2.3中介紹的,還是啟動(dòng)對(duì)應(yīng)的應(yīng)用程序來(lái)實(shí)現(xiàn)煎饼。比如發(fā)短息:adb shell am start -a android.intent.action.SENDTO -d smsto:發(fā)送號(hào)碼?--es sms_body 短信內(nèi)容讹挎。那么如何讀取一條短信內(nèi)容呢?
在編寫pyapp框架的過程中為了實(shí)現(xiàn)app的驗(yàn)證碼自動(dòng)填寫功能吆玖,著實(shí)費(fèi)了一番功夫筒溃。目前大部分的注冊(cè)登錄都是可以用動(dòng)態(tài)短信驗(yàn)證碼來(lái)進(jìn)行操作的,當(dāng)然app開發(fā)者本身是可以實(shí)現(xiàn)在收到短信后讀取驗(yàn)證碼進(jìn)行自動(dòng)填寫沾乘,遇到?jīng)]有這種功能的app我們當(dāng)然也可以按照此原理去實(shí)現(xiàn)怜奖。由于安卓手機(jī)的所有短信都是存儲(chǔ)在數(shù)據(jù)庫(kù)中,那么我們只要找到短信的這個(gè)數(shù)據(jù)庫(kù)文件翅阵,自然就可以輕松的通過python的數(shù)據(jù)庫(kù)操作讀取到短信內(nèi)容了歪玲。'/data/data/com.android.providers.telephony/databases/mmssms.db'這個(gè)路徑下“mmssms.db”文件就是保存短信內(nèi)容的數(shù)據(jù)庫(kù)文件,那么剩下的工作自然就是數(shù)據(jù)庫(kù)的讀操作了掷匠,用正則表達(dá)式匹配到驗(yàn)證碼即可滥崩,最后通過adb的input命令寫入到app中即可。這里還需要注意的是讹语,操作“mmssms.db”文件需要root權(quán)限钙皮,所以你要想在pyapp框架里使用這個(gè)功能必須是使用root過的手機(jī)設(shè)備。
1.2.5 adb命令su權(quán)限如何使用?
什么是adb命令的su權(quán)限株灸,舉個(gè)簡(jiǎn)單的例子崇摄,比如說(shuō)你要訪問手機(jī)的內(nèi)存/data/system路徑下的文件。在cmd命令窗中你需要執(zhí)行三步:
[if !supportLists]1.?[endif]在cmd窗體中輸入命令:adb?shell回車
[if !supportLists]2.?[endif]輸入su回車
可以看到命令符由$變成了#符號(hào)慌烧。
[if !supportLists]3.?[endif]輸入cd?/data/system
這樣就完成了/data/system路徑的訪問逐抑,如果遇到那些需要權(quán)限的文件你沒有執(zhí)行su的話,可能就會(huì)給你返回一句Permission?denied(權(quán)限拒絕)屹蚊。
好了厕氨,說(shuō)了這么多上面都是在cmd窗口中去分步執(zhí)行的,那么在python中怎么去實(shí)現(xiàn)呢汹粤?如果按照之前講解的方式在python腳本中分別執(zhí)行這三條命令命斧,肯定是不行的。因?yàn)槌绦驁?zhí)行一次adb命令嘱兼,就會(huì)建立一個(gè)獨(dú)立的進(jìn)程国葬,所以我們?cè)谀_本中不能按順序執(zhí)行三次adb命令,這樣是達(dá)不到效果的芹壕。我們必須讓一條adb命令一次完成所有的步驟的執(zhí)行才對(duì)汇四,那么我們這條命令該怎么寫呢?簡(jiǎn)單暴力點(diǎn)踢涌,像這樣:adb?shell su cd data\system
肯定是不行的通孽,不過大致意思是對(duì)的,只是具體寫法上要按照正確的格式在su后面加上-c就行了睁壁。如:adb?shell su –c?cd “data\system”背苦。我們看看這條命令,注意以后需要su權(quán)限的adb命令都可以這樣寫潘明,-c后面跟著具體的操作命令即可行剂。
1.2.6 uiautomatorviewer 和hierarchyviewer傻傻分不清楚?
大家在做android自動(dòng)化測(cè)試時(shí)钳降,必定會(huì)需要知道界面元素/控件的相關(guān)屬性硼讽,如id,class等牲阁,這時(shí)在androidsdk的tool工具中就會(huì)用到uiautomatorviewer 和hierarchyviewer。這兩個(gè)工具都可以很直觀的方便大家去查找界面元素壤躲,而這樣只是單純的人工借助工具去查看城菊,既然是要做自動(dòng)化測(cè)試,必然我們要去通過代碼編程去代替手工操作了碉克。在pyapp框架中凌唬,我也是利用uiautomatorviewer來(lái)捕獲app界面的從而獲取對(duì)應(yīng)的元素/控件。接下來(lái)我們就來(lái)看看python是如何做到的漏麦。相對(duì)來(lái)說(shuō)uiautomatorviewer的實(shí)現(xiàn)更容易些客税,一條adb命令就可以了况褪。
order='adb -s device shell uiautomator dump'
運(yùn)行成功后會(huì)返回:
“UI hierchary dumped to: /storage/emulated/legacy/window_dump.xml“
結(jié)果很直觀了,這個(gè)window_dump.xml里就是整個(gè)界面的布局層級(jí)信息更耻,從中我們就可以獲取到各個(gè)元素/控件的屬性信息测垛。如果利用瀏覽器打開xml文件大家也可以直觀的看到界面的層級(jí)關(guān)系,如果大家只關(guān)心具體的元素控件秧均,我們可以在命令后面加上—compressed食侮,這樣獲取的xml就會(huì)清爽許多。
我們接著看看怎么在python中利用hierarchyviewer實(shí)現(xiàn)元素/控件獲取目胡,首先我們要知道要實(shí)現(xiàn)hierarchyviewer的元素獲取我們要打開手機(jī)的View Server服務(wù)锯七,并與其進(jìn)行socket通信,從而獲取到元素/控件信息誉己。那么接下來(lái)我們將通過幾條不同的adb命令來(lái)準(zhǔn)備好與View Server進(jìn)行通信的環(huán)境眉尸。
第一步:
通過“adb shell service call window 3”命令得到返回值Result: Parcel(00000000 00000001 ??'........')或者Result: Parcel(00000000 00000000???'........')如果是00000001表示View Server是開啟的,反之我們就要開啟View Server服務(wù)巨双。
第二步:
如果View Server沒有打開噪猾,我們就通過“adb shell service call window 1 i32 4939”命令打開。然后再通過第一步的命令確認(rèn)是否開啟了View Server炉峰。
第三步:
當(dāng)我們開啟了服務(wù)后畏妖,需要再將手機(jī)的4939端口映射到電腦的4939端口,這樣就可以進(jìn)行socket通信了疼阔。命令為“adb forward tcp:4939 tcp:4939”
以上這三步完成后戒劫,接下來(lái)我們就可以在python腳本中與View Server建立socket通信了。由于已經(jīng)有服務(wù)端View Server婆廊,我們只需要用python實(shí)現(xiàn)客戶端的socket代碼即可迅细。
import?socket#導(dǎo)入socket模塊
sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)#建立TCP連接
sock.connect(('127.0.0.1',4939))#連接服務(wù)端地址及端口并建立連接
sock.send('list')#發(fā)送list命令向服務(wù)端
sock.recv(1024)#接收返回結(jié)果
這里就不去講解python的socket用法了,重點(diǎn)講解一下這里的list指令淘邻。當(dāng)我們建立好與View Server的通信后茵典,就可以發(fā)送不同的指令向服務(wù)端,獲取信息了宾舅,這里的list意思就是獲取當(dāng)前手機(jī)活動(dòng)界面的信息统阿。如下圖
有了這個(gè)信息,我們就可以繼續(xù)發(fā)送dump命令去獲取具體某個(gè)界面的詳細(xì)層級(jí)信息了筹我。舉個(gè)例子比如我們要打印出上圖中第二行
“432b8608 com.miui.home/com.miui.home.launcher.Launcher”
的界面信息扶平,在我們發(fā)送內(nèi)容中應(yīng)該這樣寫sock.send(“dump?432b8608”),獲取結(jié)果如下圖。由于內(nèi)容會(huì)比較多蔬蕊,建議大家在代碼中將返回值寫入txt文件中结澄,方便查看。具體的內(nèi)容中每一段表示一個(gè)元素,里邊詳細(xì)的列舉了元素的各種屬性信息麻献,如id们妥,class,坐標(biāo)等勉吻。
至此监婶,我們了解到通過發(fā)送list,dump兩個(gè)命令可以進(jìn)行元素信息的獲取餐曼。另外還有一個(gè)capture命令可以獲取到元素在界面中的截圖压储,這里就不再贅述了。至于到底是用uiautomatorviewer 還是hierarchyviewer去實(shí)現(xiàn)元素的獲取源譬,決定權(quán)就在你的手上了集惋。
好了,有關(guān)python自動(dòng)化測(cè)試應(yīng)用-第11篇(APP測(cè)試)之a(chǎn)db命令(下篇)就寫到這里踩娘。本篇著重講解了一些非常規(guī)的adb命令的使用刮刑,盡可能的貼住適合我們做自動(dòng)化測(cè)試相關(guān)的adb’命令使用,或者說(shuō)是針對(duì)我在寫pyapp時(shí)實(shí)現(xiàn)的一些比較實(shí)用的adb’命令养渴。最后再聲明本文不去列舉adb命令雷绢,網(wǎng)上資料有很多,最后希望本篇文章能夠幫助到大家理卑。我是你們的lamecho辣么丑翘紊。
同時(shí)歡迎大家下載使用pyswat,pyapp自動(dòng)化測(cè)試框架藐唠。
原創(chuàng)文章帆疟,轉(zhuǎn)載請(qǐng)注明出處。
歡迎關(guān)入群”631466916“宇立,獲取最新pyswat和pyapp程序