前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >基于Appium实现深度UI遍历工具(四)代码实现篇(上)

基于Appium实现深度UI遍历工具(四)代码实现篇(上)

作者头像
雷子
发布2022-05-21 11:10:59
发布2022-05-21 11:10:59
94800
代码可运行
举报
运行总次数:0
代码可运行

系列文章:

基于Appium实现深度UI遍历工具

基于Appium实现深度UI遍历工具(二)

基于Appium实现深度UI遍历工具(三)

终于来到了代码编写的地方了,提前预告,所有代码都将放到github上面,作为我开源的项目,并且在以后会进行维护。文末我会贴上开源地址。

我们去创建项目appium_uicrawler,然后去创建前一篇文章所提到的目录,

在配置文件中,我们配置一些常用的数据,在run.py作为项目的主入口,待测的apk放到了installapk ,安装和获取包名等都通过这个获取。

上面是大概的目录结构,接下来,就是去编写一些常用的配置文件,作为运行遍历测试的一些配置,用yaml文件来编写,方便维护。这个配置文件和config不一样,config用来是代码中的一些通用的数据,yaml文件是遍历的策略,后期我们根据yaml文件配置去初始化UI遍历配置执行。

配置的yaml 起名config.yaml,放在file路径下,执行获取配置文件。后期可以灵活的路径,这里配置一个兜底策略,如果加载不到最新的,我们就依据这个兜底的策略来执行。可以执行在默认的里面来配置,初始化的策略如下

代码语言:javascript
代码运行次数:0
复制
LOGINELEMENT:
  #开启自动登录功能
  AUTOLOGIN: false

  #Android 登录相关元素及操作
  LOGIN_ELEMENTS_ANDROID:
    - ANDROID_USERNAME:
        XPATH: '//*[@resource-id="login"]'
        ACTION: input
        VALUE: '13691034101'
    - ANDROID_PASSWORD:
        XPATH: '//*[@resource-id="password"]'
        ACTION: input
        VALUE: '123456'
    - ANDROID_LOGIN_BUTTON:
        XPATH: '//*[@resource-id="test_login_button"]'
        ACTION: click
        VALUE: '1'
#全局配置
GENERAL:

  #点击次数
  MAX_CLICK_COUNT: 10000
  #查找元素的时间
  DEFAULT_WAIT: 0.2
  #查找元素的间隔时间
  INTERVAL_SEC: 0.1
  #是否忽略Crash,设为true时,
  IGNORE_CRASH: true
  #运行时间限制(分钟)
  RUNNING_TIME: 100
  #滑动次数 页面无变化是否滑动下,
  SCPRE_AUTO: true
  #滑动次数 页面无变化互动次数
  SCPRE_NUM: 2
  #控制是否生成截图, false时不会生成截图 但能提高运行速度
  SCREEN_SHOT: true
  #控制是否生成视频
  VIDEO: true
  #Crash时截图显示步骤数量
  CRASH_PIC_COUNT: 10
  #遍历深度
  MAX_DEPTH: 800
LIST:
  #tarbar
  ANDROID_BOTTOM_TAB_BAR_ID: '@resource-id="com.qihoo.browser:id/title"'
  #输入文本的类型
  INPUT_CLASS_LIST:
    - android.widget.EditText

  #待输入的文本 按照1:1等比例
  INPUT_TEXT_LIST:
    - 'leizi'
    - '123'

  #UI元素中出现下列文字时 触发back键(iOS 由左向右划触发返回操作)
  PRESS_BACK_TEXT_LIST:
    - 返回
    - 隐私协议

  #当pp跳转到以下app时 触发back键
  PRESS_BACK_PACKAGE_LIST:
    - com.android.settings

  #当前遇到以下Activity时 触发back键
  PRESS_BACK_ACTIVITY_LIST:
    - com.autohome.mainlib.business.ui.commonbrowser.activity.CommBrowserActivity

  #不点击包含以下文本的控件
  ITEM_BLACKLIST:
    - 客服
    - 退出
    - 电话
    - 拒绝
    - 拍照
    - 禁止
    - 呼叫
    - 低电量模式

  #除了APP本身的包名外 根据以下包名判断是否跳出了APP,当app跳转到以下app时被认为是合法,会继续遍历操作,待实现
  ANDROID_VALID_PACKAGE_LIST:


  #白名单,遇到包含以下文本的控件,会多次点击(默认所有控件只点一次)这里在UI遍历使用
  ITEM_WHITE_LIST:
    - 确定
    - 允许
    - 取消
    - 提交
    - 取消

  #不点击以下类型控件及其子元素
  IOS_EXCLUDE_BAR:
    #键盘
    - XCUIElementTypeKeyboard

  #不点击以下类型的元素
  IOS_EXCLUDE_TYPE:
    - XCUIElementTypeApplication

  #不点击以下类型的元素
  ANDROID_EXCLUDE_TYPE:
    - android.widget.ImageButton

对Ui遍历执行时长,是否自动登录等做了初始化配置,我们去编写读取配置的文件。

代码语言:javascript
代码运行次数:0
复制
import yaml


class Parse(object):
    def __init__(self, filepath):
        self.filepath = filepath
        self.reslut = {}
        self.reslut = self.__init()

    def __init(self):
        file = open(self.filepath, 'r', encoding="utf-8")
        file_data = file.read()
        file.close()
        self.reslut = yaml.load(file_data)
        return self.reslut

    def getlogin(self):
        return self.reslut['LOGINELEMENT']

    def getgeneral(self):
        return self.reslut['GENERAL']

    def getlist(self):
        return self.reslut['LIST']

    def get_tar(self):
        return self.getlist()['ANDROID_BOTTOM_TAB_BAR_ID']

    def get_text_input(self):
        return self.getlist()['INPUT_CLASS_LIST']

    def get_sendText(self):
        return self.getlist()['INPUT_TEXT_LIST']

    def get_back(self):
        return self.getlist()['PRESS_BACK_TEXT_LIST']
    def get_back_packname(self):
        return self.getlist()['PRESS_BACK_PACKAGE_LIST']

    def get_activity(self):
        return self.getlist()['PRESS_BACK_ACTIVITY_LIST']

    def get_block(self):
        return self.getlist()['ITEM_BLACKLIST']

    def get_white(self):
        return self.getlist()['ITEM_WHITE_LIST']

    def get_not_click(self):
        return self.getlist()['ANDROID_EXCLUDE_TYPE']

    def get_ios_bar(self):
        return self.getlist()['IOS_EXCLUDE_BAR']

    def get_run_time(self):
        return self.getgeneral()['RUNNING_TIME']

    def get_ignor_crash(self):
        return self.getgeneral()['IGNORE_CRASH']

    def get_find_element_wait(self):
        return self.getgeneral()['INTERVAL_SEC']

    def get_find_element_timeout(self):
        return self.getgeneral()['DEFAULT_WAIT']

    def get_click_ccont(self):
        return self.getgeneral()['MAX_CLICK_COUNT']

    def get_max_deep(self):
        return self.getgeneral()['MAX_DEPTH']

    def crashPic(self):
        return self.getgeneral()['CRASH_PIC_COUNT']

    def screen(self):
        return self.getgeneral()['SCREENSHOT_COUNT']

    def vido(self):
        return self.getgeneral()['VIDEO']

    def issceern(self):
        return self.getgeneral()['SCREEN_SHOT']
    def opearlogin(self):
        all_login=[]
        reslut=self.getlogin()['LOGIN_ELEMENTS_ANDROID']
        for item in reslut:
            for key,value in item.items():
                all_login.append(value)
        return all_login

    def getmonkeyConfig(self):
        return self.reslut['MONKEYCONFIG']

    def auto_loggin(self):
        return  self.getlogin()['AUTOLOGIN']

    def  scoreauto(self):
        return  self.getgeneral()['SCPRE_AUTO']

    def autoscorecount(self):
        return  self.getgeneral()['SCPRE_NUM']

编写完成后,初步的一个读取配置的脚本,我们就封装完成了,上面是对于脚本的读取,没有什么逻辑,就是正常的读取文件,然后读取yaml的配置。yaml文件读取也是非常简单的,而且读取后都是dict,去解析对应的dict即可。

在运行的过程中,还需要获取,执行过程的测试日志,我们去封装一个执行过程获取日志的方法。创建execlog.py

代码语言:javascript
代码运行次数:0
复制
import os
def run_adb_log(dev, path):
    '''
    执行adb 获取log
    '''
    cmd = 'adb -s {} shell logcat -c'.format(dev)
    os.system(cmd)
    filepath = os.path.join(path, dev)
    cmdlog = 'adb -s {} logcat -v threadtime >{}.log'.format(dev, filepath)
    os.system(cmdlog)

这里呢,只是用python执行了adb命令,在启动的时候,要想获取日志,用一个单独的线程/进程去处理这个即可。

针对运行过程的日志,即对我们代码的日志做记录,创建log.py

代码语言:javascript
代码运行次数:0
复制
import os
import logbook
from logbook.more import ColorizedStderrHandler
from functools import wraps
from common.Makecasenum import call_num
check_path = '.'
LOG_DIR = os.path.join(check_path, 'testlog')
if not os.path.exists(LOG_DIR):
    os.makedirs(LOG_DIR)
def get_logger(name='UI_bianli', level=''):
    """ get logger Factory function """
    logbook.set_datetime_format('local')
    ColorizedStderrHandler(bubble=False, level=level).push_thread()
    filename = name + call_num
    logbook.FileHandler(
        os.path.join(LOG_DIR, '%s.log' % filename), bubble=True, encoding='utf-8').push_thread()
    return logbook.Logger(name)
LOG = get_logger(level='INFO')

这里面用到的Makecasenum

代码语言:javascript
代码运行次数:0
复制
import datetime
import hashlib


def make_md5(make_user):
    md5make = hashlib.new('md5', make_user.encode('utf-8')).hexdigest()
    return md5make
call_num = make_md5(datetime.datetime.now().strftime('%Y-%m-%d-%H:%M'))

根据时间戳去形成的一个md5作为一个标识。

本次分享了通用策略的配置,读取的模块,运行log以及手机日志记录的模块。下一篇分享webdriver的封装等代码。

另外appium环境搭建可以参考

一文带你趟过mac搭建appium测试环境的遇到的坑

所有代码地址:

代码语言:javascript
代码运行次数:0
复制
https://github.com/liwanlei/appium_uicrawler

发现问题,解决问题。遇到问题,慢慢解决问题即可。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-05-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 雷子说测试开发 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档