【Android之實踐】monkeyrunner採用物件id,進行UI自動化操作
獲取物件名id方法:
1、步驟1:在sdk的tools目錄下(比如:E:\sdk\tools),啟動hierarchyviewer.bat
2、步驟2:用load view hierarchy中,獲取物件id和節點值;
3、步驟3:Inspect Screenshot中,獲取物件的X軸和Y軸值偏差值;(注:在處理對話方塊和重複id時,會用到此方法獲取偏差值)
日誌配置檔案(logging.conf):
#Configuration for log output
[loggers]
keys=root,xzs
[handlers]
keys=consoleHandler,fileHandler,rotatingFileHandler
[formatters]
keys=simpleFmt
[logger_root]
level=DEBUG
#handlers=consoleHandler
#handlers=fileHandler
handlers=rotatingFileHandler
[logger_xzs]
level=DEBUG
handlers=rotatingFileHandler
qualname=xzs
propagate=0
[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=simpleFmt
args=(sys.stdout,)
[handler_fileHandler]
class=FileHandler
level=DEBUG
formatter=simpleFmt
args=("E:\\Android SDK\\project\\result\\log\\TestDase.log", "a")
[handler_rotatingFileHandler]
class=handlers.RotatingFileHandler
level=DEBUG
formatter=simpleFmt
args=("E:\\Android SDK\\project\\result\\log\\TestCase.log", "a", 20*1024*1024, 10)
[formatter_simpleFmt]
format=%(asctime)s - %(name)s - %(levelname)s : %(message)s - [%(filename)s:%(lineno)s]
datefmt=
python程式碼:
#!/usr/bin/env monkeyrunner
# coding=UTF-8
# Copyright 2010, The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#
http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from com.android.monkeyrunner import MonkeyRunner as mr
from com.android.monkeyrunner import MonkeyDevice as md
from com.android.monkeyrunner import MonkeyImage as mi
from com.android.monkeyrunner.easy import EasyMonkeyDevice
from com.android.monkeyrunner.easy import By
from com.android.chimpchat.hierarchyviewer import HierarchyViewer
import subprocess
import sys
import os
import time
import datetime
import itertools
import hashlib
import socket
import re
import collections
import xml.dom.minidom
import logging
import logging.config
'----------------------------------設定日誌------------------------------------'
#日誌
def log(message):
CONF_LOG = "E:\Android SDK\project\conf\logging.conf"
logging.config.fileConfig(CONF_LOG); # 採用配置檔案
logger = logging.getLogger()
logger.info(message)
'--------------------------------設定思考時間-----------------------------------'
#設定思考時間
def thinking_time(ptime):
start_time = datetime.datetime.now()
print "Start thinking time is: %s" % start_time
time.sleep(ptime)
log('Thinking time is:' + str(ptime))
end_time = datetime.datetime.now()
print "End thinking time is: %s" % end_time
used_time = end_time - start_time
Final_use_time = str(used_time.seconds) + '.' + str(used_time.microseconds)
print "Final thinking time is : %s" % Final_use_time
return Final_use_time
'-------------------------------設定開始和結束事務-------------------------------'
#開始事務
def Transaction_start(name):
if '' != name:
starttime = start_time()
print 'Transaction '+'"'+ name + '"' ' started. '
log('Transaction '+'"'+ name + '"' ' started.')
return name
else:
print 'Start Transaction name cannot be empty!'
log('Start Transaction name cannot be empty!')
#結束事務,且計算用時
def Transaction_end(name,End_mark):
if '' != name:
if 'LAST' == End_mark and '' != End_mark :
endtime = end_time()
used_time = endtime - starttime
Final_use_time = str(used_time.seconds) + '.' + str(used_time.microseconds)
print 'Transaction '+'"'+ name + '"' ' ended with "Pass" status'+'(Duration: ' + Final_use_time +').'
log('Transaction '+'"'+ name + '"' ' ended with "Pass" status'+'(Duration: ' + Final_use_time +').')
return Final_use_time
else:
print 'End_mark Input error!'
log('End_mark Input error!')
else:
print 'End Transaction name cannot be empty!'
log('End Transaction name cannot be empty!')
#開始時間
def start_time():
start_time = datetime.datetime.now()
#print "Start time is: %s" % start_time
return start_time
#結束時間
def end_time():
end_time = datetime.datetime.now()
#print "End time is: %s" % end_time
return end_time
'----------------------------根據check結果建立資料夾-----------------------------'
#建立資料夾名,按用例名
def Create_Folder_name(name,status):
filename_path='E:\\Android SDK\\project\\result\\'+name
if os.path.exists(filename_path):
print 'Folder already exists!'
return Create_filename(filename_path,name,status)
else:
os.mkdir(filename_path)
return Create_filename(filename_path,name,status)
#建立檔名,按用例執行的check狀態+日期規則生成
def Create_filename(filename_path,name,status):
timeformat = '%Y%m%d%H%M%S'
create_filename_path=filename_path+'\\'+name+'_'+str(status)+'_'+str(time.strftime(timeformat))+ '.png'
print create_filename_path
log('當前建立檔案為:'+create_filename_path)
return create_filename_path
'-----------------------------對話方塊處理和重複id處理-----------------------------'
#獲取子節點
def getChildView(device,parentId, childSeq):
hierarchyViewer = device.getHierarchyViewer()
str_getchildview="hierarchyViewer.findViewById('" + parentId+"')"
for index in childSeq:
str_getchildview+=('.children[' + str(index) + ']')
exec 'child_view=' + str_getchildview
return child_view
#對話方塊事件處理操作,公共方法
def Dialog_Click(device,offset_DialogBox_x,offset_DialogBox_y,ID,byte_ID):
easy_device=EasyMonkeyDevice(device,)
print "---------Select Dialog Button---------"
try:
#select Dialog button
hierarchy_viewer = device.getHierarchyViewer()
#通過tools檔案中hierarchyviewer工具獲取子節點位置,比如content父節點,(0,2,2)就是子節點位置
#獲取確認按鈕節點位置
Dialog_button=getChildView(device,ID,byte_ID)
#Dialog_button=getChildView(device,ID,3,0,0)
except:
log( 'Error,Can not find Dialog button!')
else:
point =hierarchy_viewer.getAbsoluteCenterOfView(Dialog_button)
offset_x = offset_DialogBox_x
offset_y = offset_DialogBox_y
log("Dialog box X axis value:" + str(point.x))
log("Dialog box Y axis value:" + str(point.y))
print "X axis value:" + str(point.x)
print "Y axis value:" + str(point.y)
button_x = point.x + offset_x
button_y = point.y + offset_y
log("Final Dialog button X axis value:" + str(button_x))
log("Final Dialog button y axis value:" + str(button_y))
print "Final X axis value:" + str(button_x)
print "Final Y axis value:" + str(button_y)
return button_x,button_y
#執行退出操作
#device.touch(button_x, button_y,md.DOWN_AND_UP)
#device.touch(1095, 572,md.DOWN_AND_UP)
'-------------------------------重新連線device裝置---------------------------------'
#重新連線裝置
def Reconnect_device(device_name):
try:
print 'start kill adb server.........'
os.system('adb kill-server')
mr.sleep(2.0)
print 'start connect devices'
os.system('adb devices')
time.sleep(5)
while True:
flag = subprocess.Popen('adb devices', shell=True, stdout=subprocess.PIPE,stderr=subprocess.PIPE).communicate()[0]
match = "List of devices attached"
index = flag.find(match)
if index < 0:
print 'sleep 5s and reset adb'
os.system('adb kill-server')
os.system('adb start-server')
else:
print'connect devices success.......'
print'start close monkey process of client.................'
close_mobile_monkey()
print'close monkey process successs..........'
break
device = mr.waitForConnection(30, device_name)
print device
return device
except Exception,e:
raise Exception
#查詢和關閉執行的monkey
def close_mobile_monkey():
p1 = subprocess.Popen('adb shell ps |grep monkey', stdout=subprocess.PIPE, stderr=subprocess.PIPE)
p2 = p1.stdout.read()
p3 = p2.split(' ')
if '' in p3:
print 'Did not find the monkey process!'
else:
for j in range(3):
for i in p3:
if i == '':
p3.remove(i)
p1 = subprocess.Popen('adb shell kill -9 %s' % p3[1], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
print 'monkey process:'
log(p3)
'------------------------------操作業務-------------------------------------'
#進入客戶端操作頁面
def Client(device):
easy_device=EasyMonkeyDevice(device)
log("-----------Into Login_page Start------------")
easy_device.touch(By.id('id/ll_casher_login'),md.DOWN_AND_UP)
log("Start entering client login page")
time.sleep(4)
#------對比最新截圖與預期圖片是否一致-----#
#獲取最新截圖
check_pic = device.takeSnapshot()
'''
#獲取指定區域的影象範圍,比如,(200,400,200,400),注意兩個括號
#result_static=check_pic.getSubImage((xxx,xxx,xxx,xxx))
'''
#獲取本地預期圖片
LoginPage_Expected_pic = mr.loadImageFromFile('E:\\Android SDK\\project\\checklist\\ClientPage\\ClientPage_Expected.png','png')
#最新獲取的圖片與預期圖片進行對比
result=check_pic.sameAs(LoginPage_Expected_pic,1.0)
if True == result:
filename=Create_Folder_name('ClientPage','Pass')
check_pic.writeToFile(filename,'png')
log("TestCase is Pass!")
print "TestCase is Pass!"
return "Pass"
else:
filename=Create_Folder_name('ClientPage','Pass')
check_pic.writeToFile(filename,'png')
log("TestCase is Fail!")
print "TestCase is Fail!"
return "Fail"
#關閉對話方塊
def close_Dialog(device,offset_DialogBox_x,offset_DialogBox_y):
log("----------------close_Upgrade---------------")
ID='id/parentPanel'
byte_ID=(3,0,0)
button_x,button_y=Dialog_Click(device,offset_DialogBox_x,offset_DialogBox_y,ID,byte_ID)
device.touch(button_x,button_y,md.DOWN_AND_UP)
'--------------------------------main主方法-----------------------------------'
#main方法
def main():
#在dos中,輸入adb devices獲取device裝置名
device_name = 'X6Y6OOHXDR'
Login_check_Status = "Fail"
LoginPage_check_Status = "Fail"
device = Reconnect_device(device_name)
#device = mr.waitForConnection(30,device_name)
if not device:
print "Couldn't get connection"
sys.exit(0)
log("Found device")
#time.sleep(3)
thinking_time(3)
print '*************************************************************'
Transaction_start('ClientPage')
print '#---------Start entering client login page--------'
LoginPage_check_Status = Client(device)
if "Pass" == LoginPage_check_Status:
print "Client_page_check success!"
else:
print "Client_page_check failed!"
print '#-----------close Dialog ----------'
#設定偏差值,用Hierarchyviewer工具獲取
#步驟1:先進入Hierarchyviewer工具,選擇包名(比如:com.android.xxx.xxx),點選Inspect Screenshot
#步驟2:選擇點選Dialog視窗頂部獲取X和Y軸偏差值
C_offset_DialogBox_x = 686
C_offset_DialogBox_y = 424
close_Dialog(device,C_offset_DialogBox_x,C_offset_DialogBox_y)
Transaction_end('ClientPage','LAST')
print '*************************************************************\n'
#time.sleep(3)
thinking_time(3)
if __name__ == '__main__':
starttime = datetime.datetime.now()
main()