系列文章:
终于来到了代码编写的地方了,提前预告,所有代码都将放到github上面,作为我开源的项目,并且在以后会进行维护。文末我会贴上开源地址。
我们去创建项目appium_uicrawler,然后去创建前一篇文章所提到的目录,
在配置文件中,我们配置一些常用的数据,在run.py作为项目的主入口,待测的apk放到了installapk ,安装和获取包名等都通过这个获取。
上面是大概的目录结构,接下来,就是去编写一些常用的配置文件,作为运行遍历测试的一些配置,用yaml文件来编写,方便维护。这个配置文件和config不一样,config用来是代码中的一些通用的数据,yaml文件是遍历的策略,后期我们根据yaml文件配置去初始化UI遍历配置执行。
配置的yaml 起名config.yaml,放在file路径下,执行获取配置文件。后期可以灵活的路径,这里配置一个兜底策略,如果加载不到最新的,我们就依据这个兜底的策略来执行。可以执行在默认的里面来配置,初始化的策略如下
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遍历执行时长,是否自动登录等做了初始化配置,我们去编写读取配置的文件。
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
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
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
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环境搭建可以参考
所有代码地址:
https://github.com/liwanlei/appium_uicrawler
发现问题,解决问题。遇到问题,慢慢解决问题即可。