【Android之实践】monkeyrunner采用对象id,进行UI自动化操作

来源:互联网 发布:nginx 泛解析 编辑:程序博客网 时间:2024/06/05 05:19

获取对象名id方法:

1、步骤1:在sdktools目录下(比如: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()


0 1