基于appium的自动化测试工具,支持多进程,性能采集分析等

本帖已被设为精华帖!,

简介

基于appium编写的自动化测试工具。使用方法简单,编写yaml文件格式的测试用例即可,无需改动任何一行代码。支持Android,多台设备并行,性能采集等。
开源地址:https://github.com/ztwo/Auto_Analysis

为什么要重复造轮子

  • 稳定:执行过程中会被异常打断,目前已经捕获这些异常,增加了判断
  • 直观:例如性能报告有横向对比,错误日志筛选等
  • 简单:无需改动一行代码即可运行测试
  • 扩展:代码封装清晰,比较容易扩展,增加解释器

环境要求

  • macOS,linux,windows
  • appium 1.5.0+
  • python 2.7

工具特性

执行编写yaml格式的testcase,执行后即可得到测试报告

  • 1:支持Android 4.2.2 以上
  • 2:支持多设备并行测试
  • 3:性能采集与横向对比,每个case均是独立结果。
  • 4:支持log采集与清洗
  • 5:对appium异常的一些封装,例如失败重试,需要点击才能安装等
  • 6:用例编写支持继承多重继承,大部分用例仅需写两个步骤即可

快速开始

  • git clone https://github.com/ztwo/Auto_Analysis.git
  • cd Auto_Analysis
  • python setup.py install
  • python demo_run.py
  • result内查看测试报告

执行效果

12

报告样式

20161123810772016-11-23pm.png

测试用例编写规范

  • 1: 需要了解yaml格式编写规范,建议使用pycharm编写,自带yaml文档检查器. yaml语法学习地址
  • 2: 用例名不可重复,会影响用例的继承

测试用例字段解释

字段 解释 演示 包含字段 是否必须
test_name 用例名 login /
test_id 用例id 0001 /
test_control_type 查找控件方式 xapth xpath, id
test_action 操作方法 click 见下表
test_control 控件 com.xx.id /
test_text 断言、输入文本 test /
test_inherit 继承用例名 login /
test_range 循环本步骤次数 2 /
test_sleep 步骤执行后,等待秒 2 /
test_wait 配合断言,等待控件秒 30 /
test_action 解释 所有字段 配合字段 辅助配合字段
click 点击 click test_control_type,test_control /
send_keys 发送文本 send_keys test_control_type,test_control,test_text /
swipe 滑动 swipe_left,swipe_right,swipe_up,swipe_down / /
assert 断言 assert test_control_type,test_control,test_text test_wait
entity 实体按键 entity_home,entity_back,entity_menu,entity_volume_up,entity_volume_down / /

完整用例范例,用例名:login

---
-
test_name: 点击跳过
test_id: 0001
test_control_type: id
test_action: click
test_control: test.joko.com.myapplication:id/button1
-
test_name: 输入帐号名
test_id: 0002
test_control_type: id
test_action: send_keys
test_control: test.joko.com.myapplication:id/editText
test_text: 199999999
-
test_name: 输入密码
test_id: 0003
test_control_type: id
test_action: send_keys
test_control: test.joko.com.myapplication:id/editText2
test_text: 9999

-
test_name: 点击登录
test_id: 0004
test_control_type: xpath
test_action: click
test_control: //android.widget.Button[contains(@text,'确定')]

-
test_name: 向上滑动页面
test_id: 0005
test_action: swipe_up
test_range: 3

-
test_name: 向下滑动页面
test_id: 0006
test_action: swipe_down
test_range: 3


主要代码分析

  • 原理:开启appium driver,解析yaml格式testcase,执行,输出报告

  • po.BasePage:封装appium driver方法


def send_key_event(self,arg):
"""
操作实体按键
:return:
"""

event_list = {'entity_home':3,'entity_back':4,'entity_menu':82,'entity_volume_up':24,'entity_volume_down':25}
if arg in event_list:
self.driver.keyevent(int(event_list[arg]))

  • po.ExecuteCase:执行case类

def get_all_case(self, path_yaml):
"""

:param path_yaml: 用例地址
:return: 返回yaml内字典,且遍历继承的信息,支持多重继承
"""


def get_case(path_yaml):
case_list = []

inherit_case_file = public.GetCase.case_yaml_file()
with open(path_yaml) as f:
for dic in yaml.load(f):
if isinstance(dic, dict):
if 'test_inherit' in dic:
inherit_case_name = dic['test_inherit']
inherit_case = inherit_case_name + '.yaml'
if inherit_case in inherit_case_file.keys():
case_list += case_list + get_case(inherit_case_file[inherit_case])

else:
case_list.append(dic)
else:
U.Logging.warn('get_case:not dic')
return case_list

return get_case(path_yaml)


def __analysis_yaml(self, path_yaml):
"""
测试用例解释器
:param path_yaml: 测试用例地址
1:每执行一条用例会记录下当前的性能


:return:
"""



  • po.integration:初始化环境
  • lib.ScreenShot:minicap截图,用于appium screen报错后,调用minicap
def phone_screen(self, width_height, filename):
"""
截图
:param width_height: 宽高
:param filename: 存储的文件名
:return:
"""


U.Logging.info('phone_screen:%s' % width_height)
self.adb.shell(
"'LD_LIBRARY_PATH=/data/local/tmp /data/local/tmp/minicap -P {}/0 -s > /data/local/tmp/{}.png'".format(
width_height, filename))
U.Logging.info('phone_screen:success')

  • lib.adbUtils:adb方法封装,几乎封装了所有常用的方法。(此处感谢testerhome某位朋友,是基于他的开源脚本扩写的,有知道的是谁的帮忙@ 下)
def last_update_time(self):
"""
查询当前屏幕应用安装更新时间
"""

for package in self.shell(
'dumpsys package %s' %
self.get_current_package_name()).stdout.readlines():
if 'lastUpdateTime' in package:
return package.split('=', 2)[1].strip()

def wifi_name(self):
"""
查询连接wifi名称
"""

for package in self.shell('dumpsys wifi').stdout.readlines():
if package.startswith('mWifiInfo'):
wifi_name = re.findall(r'SSID:([^"]+), BSSID', package)
if not wifi_name:
return None
else:
return wifi_name[0].strip()

  • lib.Utils:封装的一些基础方法,如创建数据库,log输出等

  • public.installApp:安装应用,且同时开启线程,监控屏幕是否有需要点击的安装按钮


def main(self):
"""
开启多线程:
线程1:安装应用
线程2:获取当前页面是否有可点击的按钮
:return:
"""

ini = U.ConfigIni()
install_file = ini.get_ini('test_install_path', 'path')
package_name = ini.get_ini('test_package_name', 'package_name')

threads = []

click_button = threading.Thread(target=self.tap_all, args=())
threads.append(click_button)
install_app = threading.Thread(
target=self.__install_app, args=(
package_name, install_file))
threads.append(install_app)
process_list = range(len(threads))

for i in process_list:
threads[i].start()
for i in process_list:
threads[i].join()

self.adb.shell('"rm -r /data/local/tmp/*.xml"')

目前缺点:

  • 1.目前不支持iOS,不支持H5,不过框架是基于appium,增加解释器即可
  • 2.测试报告样式略丑,因为样式是纯html,不会js,得慢慢改

正在完善

  • 1.对于执行过程中异常的梳理,例如低电量,其实已经实现,但会影响执行设备的性能。还需要再打磨
  • 2.错误信息的完善

开源地址:https://github.com/ztwo/Auto_Analysis

* 注:本文来自网络投稿,不代表本站立场,如若侵犯版权,请及时知会删除