眾所周知,安卓單台設備的UI自動化測試已經比較完善了,有數不清的自動化框架或者工具。但是介紹多設備管理的內容並不多,當手里的手機多了之后,要做自動化測試平台,這塊的東西又不得不碰,擺脫USB限制,接入WiFi,才能更加自由
框架介紹
1.ATX
ATX(AutomatorX) 是一款開源的自動化測試工具,支持測試iOS平台和Android平台的原生應用、游戲、Web應用。 使用Python來編寫測試用例,混合使用圖像識別,控件定位技術來完成游戲的自動化。附加專用的IDE來完成腳本的快速編寫。
atx-agent
運行在手機的內部,為手機增加了遠程控制,自動化的功能。atx-server
最重要的功能,是將atx-agent
匯總到一個網頁上展示,並提供一個API可以獲取所有設備的列表
2.uiautomator
UIAutomator是為數不多的Android官方支持的自動化框架之一,UIAutomator隨着Android版本發布而更新。作為基於控件的自動化框架,UIAutoamtor的整體框架及API簡單明晰,非常容易上手,發布后便受到了不少開發人員的好評,但仍有部分開發人員覺得不支持resourceId檢索控件有點兒可惜。官方在隨后的Level 18中彌補了這一缺憾,至此,UIAutomator便在自動化測試領域占據了一席之地,滿足了大部分開發人員的需求。
UIAutoamtor較於其他自動化框架有什么特性呢?筆者覺得可以用粗暴但靈活、簡單可依賴來形容,其細數的優勢有很多,
概括起來有以下幾點
官方支持更新: Android原生支持,測試依賴環境少,創建方便。·
層次接口明晰: 框架層次結果分明,API明晰,上手成本很低。
基於控件交互: 支持Android原生控件解析,比坐標交互兼容性更強。
不依賴於源碼: 測試過程基於黑盒進行,對所有發行版本都可以測試。
事件等待優秀: 在事件等待方面接口豐富,控制靈活精確,表現優秀。
支持跨進程測試: 在自動化框架中,具備此特性的不多,測試范圍在ROM。
在技術選型方面,除了涉及Web的測試,UIAutomator基本上都可以幫用戶實現。如果用戶想做ROM層級的測試,或是App間
協作需跨進程的測試,那UIAutomator將是非常好的選擇;用戶渴望寫出簡單易懂而功能強大的代碼,也不妨選擇一
試,UIAutomator可以讓用戶在事件等待方面看到它優雅的一面;沒有代碼沒關系,想要競品對比也可以,單元測試、性能測
試、壓力測試,UIAutomator都可以成為用戶的選擇;簡單而不簡約,留給開發人員更自由的發揮空間,輕巧靈動,強大可靠,
這就是UIAutomator
3.python-uiautomator2
python-uiautomator2封裝了谷歌自帶的uiautomator2測試框架,提供便利的python接口。他允許測試人員直接在PC上編寫Python的測試代碼,操作手機應用,完成自動化,大大提高了自動化代碼編寫的效率。
如圖所示,python-uiautomator2主要分為兩個部分,python客戶端,移動設備
- python端: 運行腳本,並向移動設備發送HTTP請求
- 移動設備:移動設備上運行了封裝了uiautomator2的HTTP服務,解析收到的請求,並轉化成uiautomator2的代碼。
整個過程
-
在移動設備上安裝
atx-agent
(守護進程), 隨后atx-agent
啟動uiautomator2服務(默認7912端口)進行監聽 -
在PC上編寫測試腳本並執行(相當於發送HTTP請求到移動設備的server端)
-
移動設備通過WIFI或USB接收到PC上發來的HTTP請求,執行制定的操作
API介紹
github:https://github.com/openatx/uiautomator2
中文翻譯:https://blog.csdn.net/qq_38071435/article/details/80003212
1、安裝:
pip install --pre uiautomator2
#或者你可以直接從github上源碼安裝
git clone https://github.com/openatx/uiautomator2
pip install -e uiautomator2
pip install pillow #截屏工具
2、初始化手機,需要的環境SDK
python -m uiautomator2 init
這個只有初始化后才可以用
pip install --pre --upgrade weditor#安裝自動化UI定位
python -m weditor#啟動
自動安裝本庫所需的設備端程序:uiautomator-server ,atx-agent ,openstf / minicap ,openstf / minitouch 可單獨下載安裝
配置工作完成
3、打開手機端口:adb forward tcp:7912 tcp:7912
連接手機:device_ip = 127.0.0.1
這個不知道干嘛的忘記了好像是是自行安裝atx-agent的時候用的
4、常用命令:
1、安裝apk:python -m uiautomator2 install $ device_ip https://example.org/some.apk
2、清緩存:python -m uiautomator2
3、停止所有應用程序:python -m uiautomator2 app-stop-all $ device_ip
4、截圖:python -m uiautomator2截圖$ device_ip screenshot.jpg
5、檢查守護線程:d.healthcheck()
6、打開調試:d.debug = true
7、獲取連接信息:d.info
8、shell命令:d.adb_shell('pwd')
9、分辨率:d.window_size()
10、查看當前應用信息:d.current_app()
11、查看序列號:d.serial
5、快速開始:
import uiautomator2 as u2
#通過WIFI
d = u2.connect('10 .0.0.1')#u2.connect_wifi('10 .0.0.1')的#別名
#通過usb獲取設備
d = u2.connect('123456f')#u2.connect_usb('123456f')的#別名
6、系統操作:
1、安裝,只指出url:d.app_install('http://some-domain.com/some.apk')
2、啟動:d.app_start(“com.example.hello_world”)#以包名稱開頭
3、停止應用:d.app_stop(“com.example.hello_world”)
d.app_clear('com.example.hello_world')
停止所有應用:d.app_stop_all()
5、推送一個文件到手機:d.push(“foo.txt的”,“/ SD卡/”)
6、推和重命名:d.push(“foo.txt的”,“/sdcard/bar.txt”)
7、推送並更改文件模式:d.push(“foo.sh”,“/ data / local / tmp /”,mode = 0o755)
8、從設備中拉取文件:d.pull(“/ sdcard / tmp.txt”,“tmp.txt”)#如果文件在設備上找不到,FileNotFoundError將會出現
d.pull(“/ sdcard / some-file-not-exist.txt”,“tmp.txt”)
7,應用連接會話:
1、啟動應用:sess = d.session(“com.netease.cloudmusic”
2、會話連接運行中的程序:sess = d.session(“com.netease.cloudmusic”
3、檢測應否崩潰:SESS(文字= “音樂”)點擊()
檢查會話是否正常:sess.running()
8,手機硬件操作
1、d.screen_on()#打開屏幕d.screen_off()#關閉屏幕
2、獲取當前屏幕狀態:d.info.get('screenOn')#android 4.4
3、按軟/硬件
d、press(“home”)#按home鍵,用鍵名
d、press(“back”)#按返回鍵,與主要的名稱
d、press(0x07,0x02)#按下鍵碼0×07(“0”)與META ALT(0x02)
d、unlock()解鎖屏幕
實踐代碼
所用到的設計模式
PageObject設計模式:
1.是將某個頁面的所有"元素(包含控件)屬性"及"元素操作"封裝在1個類(Class)里面~~~~
- 目的: 測試代碼與被測頁面對象代碼分離,后期如果有頁面元素發生了更改,只需要修改相應頁面對象的代碼(即對應Class文件),而不需要修改測試代碼
- 盡量采用xpath方式來尋找頁面元素,而不建議使用name,Link等方法; xpath是基於頁面元素所處區域,一般不會發生變化,測試代碼基本不受干擾.
- 將頁面元素屬性信息與代碼分離,即與被測對象代碼分離,目的也是為了進一步降低后續因頁面變化帶來的維護成本
def install(d):#安裝元素選擇 lists = ["com.kingroot.kinguser:id/button_right", "vivo:id/vivo_adb_install_ok_button", "android:id/button1", "com.android.packageinstaller:id/decide_to_continue"] while True: for i in lists: anzhuang(i,d) def anzhuang(string,d):#元素觸發 try: s = d(resourceId=string) if s.exists: s.click() except: pass
從ATX-server中獲取當前可用設備列表
1.在 ATX server自帶的設備管理頁面中,列出了當前可用的設備列表。於是嘗試從這個頁面的網絡請求中獲取設備列表,果然有收獲:
從 list 這個請求中,通過 present 屬性,獲取當前可用的設備列表,就可以逐個調用進行測試了。
def getDevices():#獲取在線ip url=r'http://192.168.1.110:8000/list'.encode() r=requests.get(url) deviceList=[] content=json.loads(r.text) for device in content: if device['present']: deviceList.append(device['ip']) print(device['ip'])
python啟動以及關閉服務
開啟服務
obj1=subprocess.Popen(['rethinkdb','--http-port','8090'],cwd=r'C:\rethinkdb-2.3.6',shell=True, stdout=subprocess.PIPE) obj2=subprocess.Popen(['atx-server','--port','8000'],cwd=r'C:\Users\外網\go\src\github.com\openatx\atx-server',shell=True,stdout=subprocess.PIPE) obj3=subprocess.Popen(['python','-m','http.server','8888'],cwd=r'C:\Users\外網\Desktop',shell=True,stdout=subprocess.PIPE)
關閉服務
subprocess.Popen('TASKKILL /F /IM rethinkdb.exe', shell=True, stdout=subprocess.PIPE) subprocess.Popen('TASKKILL /F /IM atx-server.exe', shell=True, stdout=subprocess.PIPE) subprocess.Popen('TASKKILL /F /IM python.exe',shell=True, stdout=subprocess.PIPE)
框架API使用
iplist=getDevices() for ip in iplist:# d = u2.connect('%s'%ip.strip()) d.unlock() d.healthcheck() d.app_uninstall_all() az=threading.Thread(target=install,args=(d,)) az.start() package=d.app_install('http://192.168.1.110:8888/T11.apk') #d.disable_popups() print(package) d.app_start(package)
Python unittest 測試框架 [中文文檔] https://github.com/xinzhen2015/unittest