基于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内查看测试报告
执行效果

报告样式

测试用例编写规范
- 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
* 注:本文来自网络投稿,不代表本站立场,如若侵犯版权,请及时知会删除
