Skip to main content
Join the official 2019 Python Developers SurveyStart the survey!

only for android ui test, base on rtsf

Project description

rtsf-app

基于rtsf测试框架,关键字驱动Android UI,进行自动化的功能测试

环境准备

window安装 appium.js

  1. 下载安装node.js
  2. 执行命令,安装cnpm: npm install -g cnpm --registry=https://registry.npm.taobao.org
  3. 执行命令,安装appium: cnpm install appium -g
  4. 安装完成后,验证appium: appium.cmd --command-timeout 120000 -p 4723 -U DEVICE_ID

appium.cmd其实就是: node "%appdata%\npm\node_modules\appium\build\lib\main.js" --command-timeout 120000 -p 4723 -U DEVICE_ID

appium-cmd.png

设置ANDROID_HOME环境变量

  1. 下载simple_android_home
  2. 解压文件android_home.zip,新增环境变量 ANDROID_HOME,为解压后的根目录的路径
  3. 在环境变量path中,追加 %ANDROID_HOME%\platform-tools

如果你安装了 android SDK,并设置了 ANDROID_HOME, 确保 adb 和 aapt命令可以被调用

android-tools.png

下载selenium-server-standalone.jar

参见rtsf-web项目,环境准备栏,给出的下载链接

安装rtsf-app

pip install rtsf-app

命令介绍

工具命令

  1. 查看设备信息, 格式: 设备id:设备属性 ,设备属性中,android_version就是设备版本,即android device platform version
# PC中,执行ainfo命令,打印该PC连接的所有设备信息及设备属性
> ainfo
{'127.0.0.1:6555': {'ip': None, 'model': 'SAMSUNG-SM-N900A', 'cpu': 'x86', 'pad_version': 'hlteatt-userdebug 4.4.4 tt eng.jenkins.20171226.140228 release-keys', 'android_version': '4.4.4', 'android_api_version': '19', 'linux_version': 'Linux version 3.10.0+ (ttvm@TianTian-Dev) (gcc version 4.6 20120106 (prerelease) (GCC) ) #13 SMP PREEMPT Mon Dec 18 11:26:12 CST 2017'}}

ainfo-cmd.png

  1. 查看apk信息,其中主要关注,appPackage和appActivity
# PC中,执行ainfo --apk APK_FILE 命令,查看apk信息
> ainfo --apk C:\ApiDemos-debug.apk
{'platformName': 'Android', 'deviceName': None, 'platformVersion': None, 'app': 'C:\\d_disk\\auto\\buffer\\test\\tools\\android\\ApiDemos-debug.apk', 'appPackage': 'io.appium.android.apis', 'appWaitPackage': 'io.appium.android.apis', 'appActivity': 'io.appium.android.apis.ApiDemos', 'unicodeKeyboard': True, 'resetKeyboard': True, 'newCommandTimeout': 120000}

场景一 本地测试

一般情况下,就是一台PC,连接一台设备的测试场景,步骤如下

1.测试场景假设

 apk(待测试的apk): C:\ApiDemos-debug.apk
 case(自动化测试用例): C:\test_case.yaml

 PC_A_IP(本机): 192.168.1.1
 PC_A_Android_Device_ID(天天模拟器): 127.0.0.1:6555

2.开启appium server,并绑定待测设备

#  PC_A,监听4723端口,该端口绑定  id为127.0.0.1:6555并且版本为4.4.4的设备;注意,监听端口+1也会被占用
> appserver 192.168.1.1:4723 --device-name 127.0.0.1:6555 --device-version 4.4.4

3.aldriver驱动测试

# aldriver命令执行本地测试,该命令主动连接本地PC_A的4723端口,并驱动adb连接的第一个设备进行测试
# 这就是为什么,在假设场景中,要求appserver使用PC_A使用本机IP和4723端口,并绑定名字是 127.0.0.1:6555 的设备
> aldriver C:\test_case.yaml --apk C:\ApiDemos-debug.apk

# 如果,你没有apk,但是通过 工具命令,获取到 appPackage和appActivity,可以使用下述命令;原理相当于appium中的,start_activity(package, activity)
#> aldriver C:\test_case.yaml --package io.appium.android.apis --activity io.appium.android.apis.ApiDemos

# 当然,也可以补全所有参数
#> aldriver C:\test_case.yaml --apk C:\ApiDemos-debug.apk --package io.appium.android.apis --activity io.appium.android.apis.ApiDemos

4.释放端口占用

ctrl + c 结束端口占用

scene-1.png

场景二 远程控制测试-Selenium Grid Mode

测试背景及分析

背景: 
    比如,手上有1000条相对独立的测试case,一台PC一台设备的方式完成这些case的验证,效率较低。那么,并行测试是最好的解决办法

分析: 
    1.多台PC连接多台设备的测试场景假设,其原理是基于selenium RC,使用selenium Grid的方式,使得appium server作为node节点,进行分布式测试
    2.可是,即使是分布式测试,它的过程也是一个并发的过程,每台设备分别都要测试1000条case。好比很多车在支路上跑,汇入的主干道却只有一条
    3.需要做的,就是让这1000条case,分配给这些设备,让它们并行测试。解决方法:多重hub

多台PC,连接多台设备,并行测试case场景,步骤如下

1.测试场景假设

 apk(待测试的apk): C:\ApiDemos-debug.apk
 case1(自动化测试用例): C:\test_case1.yaml
 case2(自动化测试用例): C:\test_case2.yaml
 ...

 PC_Server_IP(Grid Hub端): 192.168.1.254

 PC_A_IP(本机): 192.168.1.1
 PC_A_Android_Device_ID(天天模拟器): 127.0.0.1:6555
 ...

 PC_B_IP(远端机): 192.168.1.2
 PC_B_Android_Device_ID(天天模拟器): 127.0.0.1:6555
 ...

注意: adb.exe最多支持每台pc链接20台设备
并行测试: PC_A连接的所有机器,测试case1;PC_B连接的所有机器,测试case2

grid-hub.png

2.开启selenium grid hub

命令详解,参见rtsf-web

# PC_Server设置PC_A的hub
> wrhub C:\selenium-server-standalone-3.14.0.jar --port 4444

# PC_Server设置PC_B的hub
> wrhub C:\selenium-server-standalone-3.14.0.jar --port 5555

3.开启appium server node

# PC_A  4723端口绑定设备,并注册node节点 
> appserver 192.168.1.1:4723 --device-name 127.0.0.1:6555 --device-version 4.4.4 --hub-ip 192.168.1.254 --hub-port 4444

# PC_A  4725端口绑定设备,并注册node节点 
> appserver 192.168.1.1:4725 --device-name DEVICE_ID --device-version DEVICE_VERSION --hub-ip 192.168.1.254 --hub-port 4444
...

# PC_B, 同理
> appserver 192.168.1.2:4723 --device-name 127.0.0.1:6555 --device-version 4.4.4 --hub-ip 192.168.1.254 --hub-port 5555
...

4.ardriver驱动测试

注意:

  • 如果使用 --apk参数,那么 确保 PC A 和 PC B,在该指定的文件路径中,存在这个apk。
  • 如果使用 --package和--activity参数,那么确保,连接到PC的手机,已经装了这个apk
  • aldriver 与 ardriver的区别就在于: ardriver支持 ip和port参数,允许grid模式
# ardriver本身是个并发驱动测试,但是,每次使用都会开一个进程,并发的过程,就采用多次执行命令吧
# PC_A执行case1,执行case1的测试验证
> ardriver C:\test_case1.yaml --apk C:\ApiDemos-debug.apk --ip 192.168.1.254 --port 4444

# PC_B的所有设备,执行case2的测试验证
> ardriver C:\test_case2.yaml --apk C:\ApiDemos-debug.apk --ip 192.168.1.254 --port 5555

测试报告及日志

执行结束后,测试用例所在路径,就是report生成的路径

编写测试用例,模板基于rtsf

变量引用-> $var 关键字(函数)引用-> ${function}

  • 常量的定义, glob_var 和 glob_regx
  • 模板常用的关键字,参见 rtsf介绍

基本用例

基本用例,是指没有分层的情况下,简单的测试用例

# test_case.yaml
# yaml测试用例,模型示例:
- project:
    name: xxx App
    module: xxx模块-功能测试

- case:
    # id desc 选填,非约定字段 
    id: ATP-1
    desc: 测试用例-模板格式的设计-模板(全字段)

    # name 必填,需确保唯一性
    name: android_app_ui_auto_test_demo_1

    # responsible 选填
    responsible: rockfeng0

    # tester 选填
    tester: rockfeng0

    # 定义正则表达式, 定义的字符串不会解析
    glob_regx:
        rex_bar_title: 'Views/Controls/(.*)'

    # 定义变量, 效果同 SetVar(name, value)
    glob_var:
        app_package: io.appium.android.apis
        app_main_activity: .ApiDemos
        app_view_webview_activity: .view.WebView1
        app_view_button_activity: .view.Buttons1
        app_view_control_activity: .view.Controls1
        app_view_dragdrop_activity: .view.DragAndDropDemo
        app_graphic_paint_activity: .graphics.TouchPaint
        app_animation_activity: .animation.BouncingBalls

    # pre_command 选填
    pre_command:
        - ${StartActivity($app_package, $app_view_control_activity)}
        - ${DyStrData(var_bar_title, $rex_bar_title)}
        - ${VerifyVar(var_bar_title, 1. Light Theme)}  

    # steps 必填
    steps:      

        # 在appdriver中,定位元素
        - appdriver:
            by: id
            value: io.appium.android.apis:id/edit
            index: 0
            timeout: 10
            action: ${SendKeys(你好  -  hello)}

        - appdriver:
            action: ${TimeSleep(1)}

        - appdriver:
            by: -android uiautomator
            value: text("Checkbox 1")
            index: 0
            timeout: 10
            action: ${Tap()}

        - appdriver:
            action: ${VerifyElemAttr(checked, true)}

        - appdriver:
            action: ${Tap()}

        - appdriver:
            action: ${VerifyElemAttr(checked, false)}

        - appdriver:
            action: ${TimeSleep(1)} 

        - appdriver:
            action: ${Swipe(up, 1)}

        - appdriver:
            by: id
            value: android:id/text1            
            action: ${Tap()} 

        - appdriver:
            by: -android uiautomator
            value: 'text("Earth")'
            action: ${Tap()}

    # post_command 选填
    post_command:
        - ${Back()}
        - ${CloseApp()}

分层用例

  • 分层用例,是指模块功能测试的时候,对测试用例进行分层,最小的单元为api,其次为suite,最后组成用例
  • 其存放路径、编写规则等,详见 rtsf相关介绍
  • 示例可以,参见rtsf-http相关介绍

封装的关键字(内置函数)

关键字的使用,在前面,有介绍,规则如下

变量引用-> $var 关键字(函数)引用-> ${function}

App functions --> android设备-测试相关常用操作

LaunchApp()                                     # use current session to launch and active the app        
StartActivity(app_package,app_activity,timeout) # Only support android.  start an activity and focus to it. default timeout is 10 seconds
PageSource()                                    # page source for this activity
Forward()                                       # 类似浏览器的 前进
Back()                                          # 类似浏览器的 后退
Shake()                                         # 模拟设备摇晃 
BackgroundApp(seconds)                          # 应用会被放到后台特定时间,然后应用会重新回到前台 
OpenNotifications()                             # 打开通知栏
RemoveApp(app_package)                          # 卸载app
SwitchToDefaultContext()                        # 切换到默认上下文 
SwitchToNewContext()                            # 切换到新的上下文
Reset()                                         # 重置app, 即先closeApp然后在launchAPP
CloseApp()                                      # only close app . keep the session
QuitApp()                                       # will close the session

AppElement methods --> 元素定位相关操作

AppElement methods 参数介绍 描述
GetControl() 获取element controls,返回字典,如:{"by":None,"value":None,"index":0,"timeout":10}
SetControl(by,value,index,timeout) by: 指appium的寻找元素的方式:NativeApp支持("id","xpath","class name",'-android uiautomator'),WebView支持selenium所用方式,默认为None 1.依据app当前context,设置element controls,用于app元素的定位和控制
2. -android uiautomator是appium使用uiautomator中的UiSelector来定位元素,常用来使用文本定位元素,value值如 text("xxxx")
value: 与by配对使用,相应by的值
index: 索引值,默认为0,即第一个, 如果by,value组合找到很多元素,通过索引index指定一个
timeout: 超时时间,默认10,即10秒,如果by,value组合寻找元素超过10秒,超时报错

AppContext methods --> 用于上下文管理

DyAttrData(name,attr)                       # -> 属性-动态存储变量,适用于,保存UI元素属性值。name-变量名称,attr为UI元素的属性名称,**配合SetControl使用**
DyActivityData(name)                        # -> 使用变量,保存当前app activity name
DyPackageData(name)                         # -> 使用变量,保存当前app package name
DyStrData(name, regx, index)                # -> 字符串-动态存储变量,适用于,保存页面html中指定的值。 name-变量名称,regx已编译的正则表达式,index指定索引,默认0


GetVar(name)                                # -> 获取指定变量的值
SetVar(name,value)                          # -> 设置指定变量的值

AppWait methods --> 用于时间的控制

TimeSleep(seconds)                   # -> 指定等待时间(秒钟)
WaitForAppearing()                   # -> 等待元素出现(可能是隐藏,不可见的),**配合SetControl使用**
WaitForDisappearing()                # -> 等待元素消失,**配合SetControl使用**
WaitForVisible()                     # -> 等待元素可见,**配合SetControl使用**

AppVerify methods --> 用于验证

VerifyVar(name, expect_value)                # -> 验证变量值,是期望的expect_value,返回True,否则返回False
VerifyAppInstalled(app_package)              # -> 验证app package name已经安装
VerifyCurrentActivity(app_activity)          # -> 验证当前app activity name是期望的app_activity
VerifyText(text)                             # -> 验证元素text属性值,为期望的text,**配合SetControl使用**
VerifyElemEnabled()                          # -> 验证元素是enabled,**配合SetControl使用**
VerifyElemNotEnabled()                       # -> 验证元素是Not Enabled, **配合SetControl使用**
VerifyElemVisible()                          # -> 验证元素是可见的, **配合SetControl使用**
VerifyElemNotVisible()                       # -> 验证元素是不可见的,**配合SetControl使用**
VerifyElemAttr(attr_name,expect_value)       # -> 验证元素属性attr_name的值,包含值expect_value,**配合SetControl使用**
VerifyElemCounts(num)                        # -> 验证元素数量为num,**配合SetControl使用**

AppTouchAction methods --> 用于Android触摸操作

Tap()                        # -> 在指定元素上,轻触点击 1次,**配合SetControl使用**
LongPress()                  # -> 在指定元素上,长按,**配合SetControl使用**
Press()                      # -> 在指定元素上,按住不释放,**配合SetControl使用**
MoveTo()                     # -> 移动到指定元素上,**配合SetControl使用**
Release()                    # -> 在指定元素上,释放按住的操作,**配合SetControl使用**
Draw()                       # -> 在当前activity中,画画
Swipe(direction, times)      # -> 在当前activity中,滑动.direction滑动方向: up, down, left, right; times滑动次数,默认1次

AppActions methods --> 用于Android常规操作

Pinch()                      # -> 在指定元素上缩小,**配合SetControl使用**
Zoom()                       # -> 在指定元素上放大,**配合SetControl使用**
SendKeys(value)              # -> 在指定元素上,输入文本值,**配合SetControl使用**, 继承自selenium,可用于WebView
click()                      # -> 在指定元素上,点击左键一次,**配合SetControl使用**, 继承自selenium,可用于WebView

AppTouchAction和AppActions,封装较少的原因是考虑到Appium继承了selenium,因此有些appium提供的方法中,并不会同时兼容NativeApp和WebviewApp,同时,rtsf-web项目已经支持了selenium对web ui的测试。

自定义,关键字(函数、变量)

在case同级目录中,创建 preference.py, 该文件所定义的 变量、函数,可以被动态加载和引用

执行用例的时候,可以使用 变量引用 或者关键字引用的方法,调用,自定义的函数和变量

# preference.py 示例

test_var = "hello rtsf."
def test_func():
    return "nihao rtsf."



Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Files for rtsf-app, version 1.2.2
Filename, size File type Python version Upload date Hashes
Filename, size rtsf_app-1.2.2-py2.py3-none-any.whl (22.9 kB) File type Wheel Python version py2.py3 Upload date Hashes View hashes
Filename, size rtsf-app-1.2.2.tar.gz (22.8 kB) File type Source Python version None Upload date Hashes View hashes

Supported by

Elastic Elastic Search Pingdom Pingdom Monitoring Google Google BigQuery Sentry Sentry Error logging AWS AWS Cloud computing DataDog DataDog Monitoring Fastly Fastly CDN SignalFx SignalFx Supporter DigiCert DigiCert EV certificate StatusPage StatusPage Status page