appium自动化测试

Appinum前置知识

app类型和区别

1556603587000

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

1556603963437

Andriod SDK

在这里插入图片描述

元素获取—UI Automator

在这里插入图片描述

adb命令实践

Android 调试桥

adb ( Android Debug Bridge)是一个通用命令行工具,其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利,如安装和调试应用。

Tips: 在 android_sdk/platform-tools/ 中找到 adb 工具,然后根据其具体的路径配置好环境变量。然后启动cmd 输入‘adb’即可查看是否配置成功。

adb 的工作原理

启动一个 adb 客户端时,此客户端首先检查是否有已运行的 adb 服务器进程。如果没有,它将启动服务器进程。当服务器启动时,它与本地 TCP 端口 5037 绑定,并侦听从 adb 客户端发送的命令—所有 adb 客户端均使用端口 5037 与 adb 服务器通信。

启用 adb 调试

要在通过 USB 连接的设备上使用 adb,您必须在设备系统设置中启用 USB debugging(位于 Developer options 下)。

在运行 Android 4.2 及更高版本的设备上,Developer options 屏幕默认情况下处于隐藏状态。如需将其显示出来,请转到 Settings > About phone 并点按 Build number 七次。返回上一屏幕,在底部可以找到 Developer options。

注:当您连接运行 Android 4.2.2 或更高版本的设备时,系统将显示一个对话框,询问您是否接受允许在这台计算机上调试的 RSA 密钥。这种安全机制可以保护用户设备,因为它可以确保只有在您能够解锁设备并确认对话框的情况下才能执行 USB 调试和其他 ADB 命令。

adb常用命令

查看adb版本
adb  version
连接夜神模拟器(此处分别演示模拟器和真机连接)
adb connect 127.0.0.1:62001

Tips:

夜神模拟器的端口是规律的,第一个模拟器端口是62001,第二个模拟器端口是62025,第三个是62025+1,依此类推。

· 模拟器1:Android 4.4.2 地址:127.0.0.1:62001

· 模拟器2: Andriod 5.1.1 地址:127.0.0.1:62025

· 更多详情:夜神安卓模拟器adb命令详解

查看设备信息
adb devices

如果出现如下提示:

adb server version (31) doesn't match this client (36); killing...
  • 原因: adb版本不对 ,Androd SDK的版本和模拟器的adb版本不一致
  • 解决方案:将Android SDK的 adb替换掉模拟器的adb即可。模拟器adb路径 :{安装Path}\Nox\bin
adb shell

android 设备底层是 linux 系统。 shell 是 linux 系统的字符交互界面。

adb shell
 
#进入指定设备shell
adb  -s 127.0.0.1:62001 shell
 
#退出adb shell
exit

进入adb shell后有两种状态显示:#代表有root权限,$代表没有root权限

root@android:/ #
 
shell@mx4:/ $

root用户是系统中唯一的超级管理员,它具有等同于操作系统的权限。一些需要root权限的应用,譬如广告阻挡,卸载系统预装App是需要root权限的。可问题在于root比windows的系统管理员的能力更大,足以把整个系统的大部分文件删掉,导致系统完全毁坏,不能再次使用。所以,用root进行不当的操作是相当危险的,轻微的可以死机,严重的甚至不能开机。所以,在Unix、Linux及Android中,除非确实需要,一般情况下都不推荐使用root。

在设备安装apk
adb install | -r <apkName>  -r 覆盖原安装文件 -s 可以指定设备
eg:
 
#默认安装
adb install "C:\Users\Shuqing\Desktop\Appium 自动化测试教程\wandoujia.apk"
 
#覆盖安装
adb install -r  "C:\Users\Shuqing\Desktop\Appium 自动化测试教程\wandoujia.apk"
 
#指定设备安装
adb  -s 127.0.0.1:62001 install  C:\Users\Shuqing\Desktop\Appium\kaoyan3.1.0.apk 自动化测试教程\wandoujia.apk"
 

如遇到报错:Failure [INSTALL_FAILED_INVALID_URI]

解决方案: cmd命令行下执行以下命令:

· 第一步、adb remount

· 第二步、adb shell

· 第三步、cd /data

· 第四步、chmod 777 local

· 重新安装apk,ok了。

卸载apk

1.首先进入设备的/data/app目录找到app包名

adb shell
cd /data/app/
 

2.执行命令删除

adb uninstall  | -k  <apkName>  卸载软件
 
adb uninstall  com.wandoujia.phoenix2

Tips:安装后的包名系统会在末尾加上-1之类的数字,要去掉才可以成功卸载。 软件名称为包名,不要包含.apk
-k 加 -k 参数,为卸载软件但是保留配置和缓存文件.

查看设备上面安装的应用包名
adb shell pm list package
文件读取写入

将文件从PC写入到设备

adb push <本地路径> <设备路径>
eg:
adb push C:\Users\Shuqing\Desktop\kyb.txt /sdcard
C:\Users\Shuqing\Desktop\kyb.txt: 1 file pushed. 0.1 MB/s (462 bytes in 0.005s)

将文件从设备读取到PC

adb pull <remote> <local>
eg:
adb pull /sdcard/server.log  C:\Users\Shuqing\Desktop
/sdcard/server.log: 1 file pulled. 0.0 MB/s (196 bytes in 0.004s)

注意:由于权限问题,不能直接pull到电脑磁盘根目录,否则会报错:

C:\Users\Shuqing>adb pull /sdcard/server.log  D:\\
adb: error: cannot create file/directory 'D:\\': No such file or directory

屏幕截图
$ adb shell screencap /sdcard/screen.png
adb pull /sdcard/screen.png  C:\Users\Shuqing\Desktop

adb服务启动和关闭
adb kill-server                        关闭adb服务
adb start-server                      开启adb服务

Tips:如果5037端口被占用可以使用如下命令释放端口

 
C:\Users\Shuqing> netstat -ano | findstr "5037"
  TCP    127.0.0.1:5037         0.0.0.0:0              LISTENING       11072
  TCP    127.0.0.1:5037         127.0.0.1:59519        TIME_WAIT       0
 
taskkill -f -pid XXX
 

小结

  1. adb是自动化非常重要的一个工具
  2. 目前很多PC客户端手机助手也是基于adb连接原理进行封装的。
  3. 可以将常用的adb命令封装成bat命令,随时可以运行。如:

adbdevices.bat

adb devices
pause

AdbConnect.bat

adb connect 127.0.0.1:62025
adb devices
pause

Package与Activity

adb shell pm list package 查看所有的package包

Package

Package 包。只是在我们的app中这个Package是唯一的,就像你身份证号码一样。在我们做app自动化时,我们就需要知道他的Package,我们知道了Package那么也就知道我们需要对哪个app做自动化。 注意和.apk文件包名不同。

Activity

Android中,activity是所有程序的根本,所有程序的流程都运行在activity之中,activity可以算是开发者遇到的最频繁,也是android当中最基本的模块之一。在android的程序中,activity一般代表手机屏幕的一屏。如果把手机比作一个浏览器,那么activity就相当于一个网页。在activity当中可以添加一些Button、Checkbox等控件,可以看到activity概念和网页的概念相当类似。

一般一个android应用是由多个activity组成的,这多个activity之间可以进行相互跳转。例如,按下一个Button按钮后,可能会跳转到其他的activity,与网页跳转稍微有点不一样的是,activity之间的跳转有可能返回值。

Tips:activity的生命周期:即“产生、运行、销毁”,但是这其中会调用许多方法onCreate(创建) 、onStart(激活) 、onResume(恢复) 、onPause(暂停) 、onStop(停止) 、onDestroy(销毁) 、onRestart(重启)。

Activity获取

研发提供

aapt

aapt即Android Asset Packaging Tool,在SDK的build-tools目录下。该工具可以查看,创建, 更新ZIP格式的文档附件(zip, jar, apk)。也可将资源文件编译成二进制文件。获取命令如下:

aapt dump badging xxxx.apk
aapt dump badging xxxx.apk | find "launchable-activity"

可以把appt配置到环境变量(系统变量中的Path),这样运行便捷一些,appt路径:\Andriod_SDK\build-tools{version}

Activity页面布局元素

FrameLayout

FrameLayout是最简单的布局了。所有放在布局里的控件,都按照层次堆叠在屏幕的左上角。后加进来的控件覆盖前面的控件。

LinearLayout

LinearLayout按照垂直或者水平的顺序依次排列子元素,每一个子元素都位于前一个元素之后。如果是垂直排列,那么将是一个N行单列的结构,每一行只会有一个元素,而不论这个元素的宽度为多少;如果是水平排列,那么将是一个单行N列的结构。如果搭建两行两列的结构,通常的方式是先垂直排列两个元素,每一个元素里再包含一个LinearLayout进行水平排列。

RelativeLayout

RelativeLayout相对布局允许子元素指定它们相对于其父元素或兄弟元素的位置,这是实际布局中最常用的布局方式之一。

AbsoluteLayout

AbsoluteLayout是绝对位置布局。在此布局中的子元素的android:layout_x和android:layout_y属性将生效,用于描述该子元素的坐标位置。屏幕左上角为坐标原点(0,0),第一个0代表横坐标,向右移动此值增大,第二个0代表纵坐标,向下移动,此值增大。在此布局中的子元素可以相互重叠。在实际开发中,通常不采用此布局格式,

TableLayout

TableLayout 为表格布局,适用于N行N列的布局格式。一个TableLayout由许多TableRow组成,一个TableRow就代表TableLayout中的一行。

TextView

通常用于显示文字用的。

ImageView

通常用于显示图片用的。

参考资料:http://www.xuebuyuan.com/1975042.html

monkey简介

Monkey简介

在Android的官方自动化测试领域有一只非常著名的“猴子”叫Monkey,这只“猴子”一旦启动,就会让被测的Android应用程序像猴子一样活蹦乱跳,到处乱跑。人们常用这只“猴子”来对被测程序进行压力测试,检查和评估被测程序的稳定性。

Moneky 路径

Monkey程序是Android系统自带的,其启动脚本是位于Android系统的/system/bin目录的Monkey文件,其jar包是位于Android系统的/system/framework目录的Monkey.jar文件。用户主要是通过adb命令来启动Monkey的,Monkey在运行时,会根据命令行参数的配置,生成伪随机的事件流,并在Android设备上执行对应的测试事件。同时,Monkey还会对测试系统进行监测,当出现以下三种情况时会进行特殊处理:

· 如限定了Monkey运行在特定包上,当监测到试图转到其他包的操作,将对其进行阻止。

· 如应用程序崩溃或接收到任何失控异常,Monkey将记录对应的错误日志,并根据命令行参数判断是停止运行还是继续运行。

· 如果应用程序发生了程序无响应(application not responding)的错误,Monkey将记录对应的错误日志,并根据命令行参数判断是停止运行还是继续运行。

· 按照选定的不同级别的反馈信息,在Monkey中还可以看到其执行过程报告和生成的事件。

Monkey启动步骤

  1. 连接移动设备
  2. 连接成功后输入命令
adb shell

  1. 进入到指定目录
cd /system/bin

4.输入 monkey命令看到如下提示则说明启动成功。

强制关闭monkey
  1. adb shell ps 查看全部在运行的进程
  2. 查找出com.android.commands.monkey 进程PID
  3. adb shell kill pid 杀掉monkey进程

monkey 命令

monkey命令格式如下:

$ adb shell monkey [options] <event-count>
  • [options] 是指monkey可传入的参数,是可选项(如果不指定options,Monkey将以无反馈模式启动,并把事件任意发送到安装在目标环境中的全部包)
  • 是指随机发送事件数。如:输入100就是执行100个伪随机事件,为必选项。

monkey事件

触摸事件、手势时间、二指缩放事件、轨迹事件、屏幕旋转事件、基本导航事件、主要导航事件、系统按键事件、启动Activity事件、键盘事件、其他类型事件

操作事件简介

Monkey所执行的随机事件流中包含11大事件,分别是触摸事件、手势事件、二指缩放事件、轨迹事件、屏幕旋转事件、基本导航事件、主要导航事件、系统按键事件、启动Activity事件、键盘事件、其他类型事件。Monkey通过这11大事件来模拟用户的常规操作,对手机App进行稳定性测试。下面让我们来详细了解这11大事件。

1.触摸事件

触摸事件是指在屏幕某处按下并抬起的操作,可通过–pct-touch参数来配置其事件百分比。从Monkey执行该事件对外输出的日志可以看到。 该事件由一组Touch(ACTION_DOWN)和Touch(ACTION_UP)事件组成,在手机上看到实际操作类似于点击。

2.手势事件

手势事件是指在屏幕某处的按下、随机移动、抬起的操作,即直线滑动操作。可通过–pct-motion参数来配置其事件百分比。

该事件是由一个ACTION_DOWN事件、一系列ACTION_MOVE事件和一个ACTION_UP事件组成的,在手机上看到的实际操作是一个没有拐弯的直线滑动操作。

3.二指缩放事件

二指缩放事件是指在屏幕上的两处同时按下,并同时移动,最后同时抬起的操作,即智能机上的放大缩小手势操作。可通过–pct-pinchzoom参数来配置其事件百分比。从Monkey执行该事件对外输出的日志可以看到:

该事件起始是一个ACTION_DOWN事件和一个ACTION_POINTER_DOWN事件,即模拟两个手指同时点下;中间是一系列的ACTION_MOVE事件,即两个手指同时在屏幕上直线滑动;结束是由一个ACTION_POINTER_UP事件和一个ACTION_UP事件组成的,即两个手指同时放开。

4.轨迹事件

轨迹事件是由一个或多个随机的移动组成的,有时会伴随着点击。很早之前的Android手机带有轨迹球,这个事件就是模拟的轨迹球的操作。现在的手机几乎都没有轨迹球,但轨迹球事件中包含曲线滑动操作,如果被测程序需要曲线滑动时可以选用此参数。可通过–pct-trackball参数来配置其事件百分比。从Monkey执行该事件对外输出的日志可以看到:

该事件是由一系列的Trackball(ACTION_MOVE)事件组成的,观察手机上的操作,即为一系列的曲线滑动操作。

5.屏幕旋转事件

屏幕旋转事件是一个隐藏事件,在Android官方文档中并没有记录这个事件。它其实是模拟的Android手机的横屏和竖屏切换。可通过–pct-rotation参数来配置其事件百分比。从Monkey执行该事件对外输出的日志可以看到: [代码] 该事件由一个rotation事件组成,其中degree表示的是旋转方向,顺时针旋转,0表示旋转90度的方向,1表示旋转180度的方向,2表示旋转270度的方向,3表示旋转360度的方向。在执行过程中,可以看到手机屏幕在横竖屏之间不断地切换。

6.基本导航事件

基本导航事件是指点击方向输入设备的上、下、左、右按键的操作,现在手机上很少有上、下、左、右按键,这种事件一般用得比较少。可通过–pct-nav参数来配置其事件百分比。从Monkey执行该事件对外输出的日志可以看到:

该事件是由一个Key(ACTION_DOWN)和一个Key(ACTION_UP)组成的,点击的就是上、下、左、右四个方向按键。

7.主要导航事件

主要导航事件是指点击“主要导航”按键的操作,这些按键通常会导致UI界面中的动作,如键盘的中间键、回退按键、菜单按键。可通过–pct-majornav参数来配置其事件百分比。从Monkey执行该事件对外输出的日志可以看到: [代码] 该事件是由一个Key(ACTION_DOWN)和一个Key(ACTION_UP)组成的,点击的按键就是中间键和菜单键。

8.系统按键事件

系统按键事件是指点击系统保留使用的按键的操作,如点击Home键、返回键、音量调节键等。可通过–pct-syskeys参数来配置其事件百分比。从Monkey执行该事件对外输出的日志可以看到: [代码] 该事件是由一个Key(ACTION_DOWN)和一个Key(ACTION_UP)组成的,点击的就是上面说到的几个系统按键。

9.启动Activity事件

启动Activity事件是指在手机上启动一个Activity的操作。在随机的时间间隔中,Monkey将执行一个startActivity()方法,作为最大限度上覆盖被测包中全部Activity的一种方法。可通过–pct-appswitch参数来配置其事件百分比。从Monkey执行该事件对外输出的日志可以看到: [代码] 该事件是由一个Switch操作组成的,从手机上看,上面的操作实际是打开了com.android.settings这个应用的一个com.android.settings.Settings的Activity界面。

10.键盘事件

键盘事件主要是一些与键盘相关的操作。比如点击输入框、键盘弹起、点击输入框以外区域、键盘收回等。可通过–pct-flip参数来配置其事件百分比。从Monkey执行该事件对外输出的日志可以看到: [代码] 如日志所示,这里主要是键盘的打开和关闭操作。

11.其他类型事件

其他类型事件包括了除前面提到的10种事件外其他所有的事件,如按键、其他不常用的设备上的按钮等。可通过–pct-anyevent参数来配置其事件百分比。从Monkey执行该事件对外输出的日志可以看到: [代码] 该事件是由一个Key(ACTION_DOWN)和一个Key(ACTION_UP)组成的,点击的按键就是其他的一些系统按键,如字母按键、数字按键等。因为现在手机很少带字母按键或数字按键,所以这个事件一般使用得比较少。

monkey参数

参数分类

  • 常规类参数
  • 事件类参数
  • 约束类参数
  • 调试类参数

常规类参数

常规类参数包括帮助参数和日志信息参数。帮助参数用于输出Monkey命令使用指导;日志信息参数将日志分为三个级别,级别越高,日志的信息越详细。

1.帮助类参数

monkey -h

2.日志级别

$ adb shell monkey -v <event-count>

-v:打印出日志信息,每个-v将增加反馈信息的级别。-v越多日志信息越详细,不过目前最多支持3个-v,即:

在这里插入图片描述
在这里插入图片描述

事件类参数

事件类参数的作用是对随机事件进行调控,从而使其遵照设定运行,如设置各种事件的百分比、设置事件生成所使用的种子值等。频率参数主要限制事件执行的时间间隔。

1.执行指定脚本

$ adb shell monkey -f <scriptfile> <event-count>
 
eg:
$ adb shell monkey -f /mnt/sdcard/test1

2.伪随机数生成种子值

使用 -s命令可以重复执行之前的伪随机操作。本身每次执行伪随机事件操作也会默认生成一个seed值

$ adb shell monkey -s <seed> <event-count>
 
eg:
$ adb shell monkey -s 666 100

3.设置间隔 如果你希望在每一个指令之间加上固定的间隔时间,可以用–throttle(注意,前面是–)命令。

$ adb shell monkey --throttle <milliseconds>
eg:
$ adb shell monkey --throttle 3000  5

–throttle:后面接时间,单位为ms(),表示事件之间的固定延迟(即执行每一个指令间隔的时间),若不接该选项,monkey将不会延迟。

4.调整触摸事件百分比

如果你希望调整触摸事件的百分比,记住使用–pct-touch。

$ adb shell monkey --pct-touch
eg:
$ adb shell monkey -v -v --pct-touch 100 200
 

–pct-touch:后面接触摸事件百分比

注意:触摸事件不单单是按键,它泛指发生在某一位置的一个down-up事件。

5.调整手势事件百分比

$ adb shell monkey --pct-motion
eg:
$ adb shell monkey -v -v --pct-motion 100 200
 

6.调整应用启动事件的百分比

如果你希望调整应用启动事件的百分比,记住使用–pct-app-switch。

$ adb shell monkey --pct-appswtich <percent>

–pct-appswitch:后面接应用启动事件百分比。

应用启动事件(即activity launches)俗称打开应用,通过调用startActivity()方法最大限度地开启该package下的所有应用。

7.调整屏幕旋转事件百分比

$ adb shell monkey --pct-rotation <percent>

–pct-rotation 后面接屏幕旋转事件的比例值。

8.其他参数

在这里插入图片描述

约束类参数

**1.**包约束

-p:后面接一个或多个包名(),如果应用需要访问其他包里的Activity,那相关的包也需要在此同时指定。如果不指定任何包,monkey将允许系统启动全部包里的Activity。

$ adb shell monkey -p <allowed-package-name> <event-count>
eg:
$ adb shell monkey -p com.tal.kaoyan 500
 
$ adb shell monkey -p com.tal.kaoyan -p com.tencent.mm 500

2.activity****类约束

如果你希望将monkey限制在一个或几个类别中,使用如下命令:

adb shell monkey -c <main-category> <event-count>

以下命令表示运行Intent.CATEGORY_LAUNCHER类别的Activity并发送1000个随机事件。

$ adb shell monkey -c Intent.CATEGORY_LAUNCHER  1000

在这里插入图片描述

调试类参数

**1.**应用程序崩溃后继续发送事件

如果你希望monkey在应用程序崩溃后继续发送事件,则需要用到–ignore-crashes命令

$ adb shell monkey --ignore-crashes <event-count> 

在设置此选项后,当应用程序崩溃或发生失控异常时,monkey将继续运行直到计数完成。如果不设置此选项,monkey遇到上述崩溃或异常将停止运行。

**2.**超时错误继续发送事件

如果你希望monkey在任何超时错误发生后继续发送事件,则需要用到–ignore-timeouts命令。

$ adb shell monkey --ignore-timeouts

–ignore-timeouts:在设置此选项后,当应用程序发生任何超时错误(如ANR,即Application Not Responding)时,monkey将继续运行直到计数完成。如果不设置此选项,monkey遇到此类超时对话框将停止运行。

**3.**应用程序权限错误发生后继续发送事件

如果你希望monkey在应用程序权限错误发生后继续发送事件,则需要用到–ignore-security-exceptions命令。

$ adb shell monkey --ignore-security-exceptions

–ignore-security-exceptions:在设置此选项后,当应用程序发生任何权限错误(如启动一个需要某些权限的Activity)时,monkey将继续运行直到计数完成。如果不设置此选项,monkey遇到此类权限错误将停止运行。

4.其他

在这里插入图片描述

Monkey参数应用综合案例

测试场景

测试考研帮app Android版。测试希望通过Monkey来模拟用户的随机操作,检查被测应用是否会出现异常(应用崩溃或者无响应)。

需求分析

1、测试是指定应用,因此需要使用-p指定被测app包名:com.tal.kaoyan

2、这个测试的目的是希望模拟用户操作,因此需要让Monkey执行的事件尽可能地接近用户的常规操作,这样才可以最大限度地发现用户使用过程中可能出现的问题。因此需要对Monkey执行的事件百分比做一些调整:

触摸事件和手势事件是用户最常见的操作,所以通过–pct-touch和–pct-motion将这两个事件的占比调整到40%与25%;目标应用包含了多个Activity,为了能覆盖大部分的Activity,所以通过–pct-appswitch将Activity切换的事件占比调整到10%;被测应用在测试中出现过不少横竖屏之间切换的问题,这个场景也必须关注,因此通过–pct-rotation把横竖屏切换事件调整到10%。

3、使用-s参数来指定命令执行的seed值 Monkey会根据seed值来生成对应事件流,同一个seed生成的事件流是完全相同的。这里指定了seed值,是为了测试发现问题时,便于进行问题复现。

4、使用–throttle参数来控制Monkey每个操作之间的时间间隔 指定操作之间的时间间隔,一方面是希望能更接近用户的操作场景,正常用户操作都会有一定的时间间隔;另一方面也是不希望因为过于频繁的操作而导致系统崩溃,尤其是在比较低端的手机上执行测试时。因此通过–throttle设置Monkey每个操作固定延迟0.4秒。

5、使用–ignore-crashs和–ignore-timeouts参数使Monkey遇到意外时能继续执行 在执行Monkey测试时,会因为应用的崩溃或没有响应而意外终止,所以需要在命令中增加限制参数–ignore-crash和–ignore-timeouts,让Monkey在遇到崩溃或没有响应的时候,能在日志中记录相关信息,并继续执行后续的测试。

6、使用-v指定log的详细级别 Monkey的日志输出有3个级别:日志的级别越高,其详细程度也越高。为了方便问题的定位,这里将日志设为 -v -v.

测试命令
adb shell monkey -p com.tal.kaoyan
--pct-touch 40 --pct-motion 25 
--pct-appswitch 10
--pct-rotation 5
-s 1666 --throttle 400
--ignore-crashes
--ignore-timeouts
-v -v  200

Monkey脚本API简介

LaunchActivity(pkg_name, cl_name):启动应用的Activity。参数:包名和启动的Activity。

Tap(x, y, tapDuration): 模拟一次手指单击事件。参数:x,y为控件坐标,tapDuration为点击的持续时间,此参数可省略。

UserWait(sleepTime): 休眠一段时间

DispatchPress(keyName): 按键。参数: keycode。 RotateScreen(rotationDegree, persist): 旋转屏幕。 参数:rotationDegree为旋转角度, e.g. 1代表90度;persist表示旋转之后是否固定,0表示旋转后恢复,非0则表示固定不变。

DispatchString(input): 输入字符串。

DispatchFlip(true/false): 打开或者关闭软键盘。

PressAndHold(x, y, pressDuration): 模拟长按事件。

Drag(xStart, yStart, xEnd, yEnd, stepCount): 用于模拟一个拖拽操作。

PinchZoom(x1Start, y1Start, x1End, y1End, x2Start, y2Start, x2End, y2End, stepCount): 模拟缩放手势。

LongPress(): 长按2秒。

DeviceWakeUp(): 唤醒屏幕。

PowerLog(power_log_type, test_case_status): 模拟电池电量信息。

WriteLog(): 将电池信息写入sd卡。

RunCmd(cmd): 运行shell命令。

DispatchPointer(downtime,eventTime,action,x,yxpressure,size,metastate,xPrecision,yPrecision,device,edgeFlags): 向指定位置,发送单个手势。

DispatchPointer(downtime,eventTime,action,x,yxpressure,size,metastate,xPrecision,yPrecision,device,edgeFilags): 发送按键消息。

LaunchInstrumentation(test_name,runner_name): 运行一个instrumentation测试用例。

DispatchTrackball: 模拟发送轨迹球事件。

ProfileWait: 等待5秒。

StartCaptureFramerate(): 获取帧率。

EndCaptureFramerate(input): 结束获取帧率。

Monkey脚本格式

脚本主要包含两部分,一部分是头文件信息,一部分是具体的monkey命令

type = raw events  
count = 1  
speed = 1.0  
//下面为monkey命令  
start data >>   
具体的monkey脚本内容  

编写脚本

kyb.txt

#头文件信息
 
type = raw events 
 
count = 1
 
speed = 1.0
 
#启动测试
start data >>
 
LaunchActivity(com.tal.kaoyan,com.tal.kaoyan.ui.activity.SplashActivity)
UserWait(2000)
 
Tap(624,900,1000) #点击取消升级
UserWait(2000)
 
Tap(806,64,1000) #点击跳过
UserWait(2000)
 
Tap(217,378,1000) #点击用户名输入框
DispatchString(zxw1234)
UserWait(2000)
 
Tap(197,461,1000) #点击密码输入框
DispatchString(zxw123456)
UserWait(2000)
 
Tap(343,637,1000) #点击登录按钮
 

执行脚本

脚本编写完成后,传到手机设备上,然后执行。

adb push C:\Users\Shuqing\Desktop\kyb1.txt /sdcard
 
adb shell monkey -f /sdcard/kyb1.txt -v 1

执行结果
C:\Users\Shuqing>adb shell monkey -f /sdcard/kyb.txt -v 1
:Monkey: seed=1524592021303 count=1
:IncludeCategory: android.intent.category.LAUNCHER
:IncludeCategory: android.intent.category.MONKEY
Replaying 0 events with speed 1.0
:Switch: #Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10200000;component=com.tal.kaoyan/.ui.activity.SplashActivity;end
    // Allowing start of Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.tal.kaoyan/.ui.activity.SplashActivity } in package com.tal.kaoyan
:Sending Touch (ACTION_DOWN): 0:(267.0,1233.0)
    // Allowing start of Intent { act=com.android.systemui.recent.action.TOGGLE_RECENTS cmp=com.android.systemui/.recent.RecentsActivity } in package com.android.systemui
:Sending Touch (ACTION_UP): 0:(267.0,1233.0)
Events injected: 5
:Sending rotation degree=0, persist=false
:Dropped: keys=0 pointers=0 trackballs=0 flips=0 rotations=0
## Network stats: elapsed time=7201ms (0ms mobile, 0ms wifi, 7201ms not connected)
// Monkey finished

注意事项

头文件代码书写注意“=”两边预留空格,否则会出现如下报错。

java.lang.NumberFormatException: Invalid int: ""

monkey日志管理

日志管理作用

Monkey日志管理是Monkey测试中非常重要的一个环节,通过日志管理分析,可以获取当前测试对象在测试过程中是否会发生异常,以及发生的概率,同时还可以获取对应的错误信息,帮助开发定位和解决问题。

monkey日志保存方法

  1. 保存在PC中
  2. 保存在手机上
  3. 标准流和错误流分开保存
保存在PC中
>adb shell monkey [option] <count> >d:\monkey.txt
 
eg:
C:\Users\Shuqing>adb shell monkey -v -v 100 >d:\monkeylog.txt

保存在手机上
C:\Users\Shuqing>adb shell
monkey -v 100 >/sdcard/monkeylog.log

注意:不能写成C:\Users\Shuqing>adb shell monkey -f /sdcard/kyb.txt -v 1 > /mnt/sdcard/monkey.log 否则会报错“系统找不到指定的路径”。

标准流和错误流分开保存

·标准流与错误流分开保存,代码如下:

Monkey [option] <count> 1>/sdcard/monkey.txt 2>/sdcard/error.txt
 
C:\Users\Shuqing>adb shell monkey -v 100 1>d:\monkey.log  2>d:\error.log

执行以上命令,Monkey的运行日志和异常日志将被分开保存。此时Monkey的运行日志将被保存在monkey.txt文件中,而异常日志将被保存在D盘下的error.txt中。

日志内容分析

运行命令:

adb shell monkey -v 100

monkeyrunner

monkeyrunner简介

MonkeyRunner工具是使用Jython(使用Java编程语言实现的Python)写出来的,它提供了多个API,通过monkeyrunner API 可以写一个Python的程序来模拟操作控制Android设备app,测试其稳定性并通过截屏可以方便地记录出现的问题。

monkeyrunner 路径:Andriod_SDK\tools

MonkeyRunner功能

1.多设备控制:API可以跨多个设备,一次启动全部模拟器来实施测试套件;

2.功能测试:为应用自动执行一次功能测试,然后观察输出结果的截屏。

3.可扩展自动化:因为monkeyrunner是一个API工具包,你可以开发基于Python模块的整个系统来控制Android设备;

Monkeyrunner与Monkey区别

monkeyrunner和money没有什么直接的关系,monkey是在设备直接运行adb shell命令生成随机事件来进行测试的。相比较而言,monkeyrunner则是通过API发送特定的命令和事件来控制设备。

monkeyrunner环境搭建

  • 安装并配置好jdk环境
  • 安装android sdk
  • 安装python 安装配置教程
  • monkeyrunner环境变量配置: {Path}\Andriod_SDK\tools
安装结果检测

在控制台输入命令:monkeyrunner出现如下显示内容则说明安装成功

C:\Users\Shuqing>monkeyrunner
Jython 2.5.3 (2.5:c56500f08d34+, Aug 13 2012, 14:54:35)
[Java HotSpot(TM) 64-Bit Server VM (Oracle Corporation)] on java1.8.0_05
>>> 

Tips:退出monkeyrunner命令行模式可以 使用快捷键 ctrl+D退出。

MonkeyRunner API

MonkeyRunner工具主要有三个类:

  1. MonkeyRunner
  2. MonkeyDevice
  3. MonkeyImage

官方API文档 :http://www.android-doc.com/tools/help/monkeyrunner_concepts.html#

1.MonkeyRunner类:

MonkeyRunner提供连接真机和模拟器、输入、暂停、警告框等方法。

在这里插入图片描述

常用方法

waitForConnection(float timeout,string deviceid),

from com.android.monkeyrunner import MonkeyRunner as mr
print("connect devices...")
 
device=mr.waitForConnection()
# device=mr.waitForConnection(5,'127.0.0.1:62001')

2.MonkeyDevice类

MonkeyDevice类提供了安装和卸载程序包、开启Activity、发送按键和点击事件、运行测试包等方法。

在这里插入图片描述

常用方法

  • installPackage (string path) 安装包
  • removePackage (string package) 卸载包
  • startActivity (string uri, string action, string data, string mimetype, iterable categories dictionary extras, component component, flags) 启动
  • touch (integer x, integer y, integer type) 点击

touch****参数说明

integer x,x坐标值。
integer y,y坐标值。
integer type,key event类型(如DOWN、UP、DOWN_AND_UP)。

DOWN为按下事件 UP为弹起事件 DOWN_AND_UP为按下弹起事件。

  • drag (tuple start, tuple end, float duration, integer steps)

drag****参数详细说明如下:

tuple start,拖拽起始位置,为tuple类型的(x,y)坐标点。
tuple end,拖拽终点位置,为tuple类型的(x,y)坐标点。
float duration,拖拽手势持续时间,默认为1.0s。
-integer steps,插值点的步数,默认值为10。

代码实现

kyb_start.py

from com.android.monkeyrunner import MonkeyRunner as mr
from com.android.monkeyrunner import MonkeyDevice as md
 
 
print("connect devices...")
device=mr.waitForConnection()
 
print("install app...")
device.installPackage(r'C:\Users\Shuqing\Desktop\kaoyan3.1.0.apk')
 
package = 'com.tal.kaoyan'
activity = 'com.tal.kaoyan.ui.activity.SplashActivity'
runComponent = package + '/' + activity
 
print("launch App...")
device.startActivity(component=runComponent)

代码执行方式

monkeyrunner scripfile
 
C:\Users\Shuqing>monkeyrunner E:\monkeyrunner_script\kyb.py

3.MonkeyImage类

MonkeyImage类在测试过程中用来保存各种格式的测试截图,并可以进行图像对比。

在这里插入图片描述

常用方法

  • takeSnapshot() 进行屏幕截图
  • writeToFile() 保存图像文件到指定的文件路径

用法示例

from com.android.monkeyrunner import MonkeyImage as mi  
print("takeSnapshot")
screenshot=device.takeSnapshot()  
screenshot.writeToFile(r'E:\monkeyrunner_script\test.png','png')  

综合实践

测试场景

  • 连接设备,自动安装并启动考研帮app
  • 启动后登录账号(账号zxw1234 密码:zxw123456),然后截图并保存到指定文件位置。

思路分析

  • 连接设备
  • 安装app
  • 启动app
  • 输入用户名密码点击登录按钮
  • 截图

脚本实现

kyb_login.py

from com.android.monkeyrunner import MonkeyRunner as mr
from com.android.monkeyrunner import MonkeyDevice as md
from com.android.monkeyrunner import MonkeyImage as mi
 
print("connect devices...")
 
device=mr.waitForConnection()
 
print(" install app")
device.installPackage(r'C:\Users\Shuqing\Desktop\kaoyan3.1.0.apk')
 
print("launch app...")
package='com.tal.kaoyan'
activity='com.tal.kaoyan.ui.activity.SplashActivity'
runComponent=package+'/'+activity
 
device.startActivity(component=runComponent)
mr.sleep(3)
 
 
print("touch cancel button")
device.touch(618,895,'DOWN_AND_UP')
mr.sleep(1)
 
 
print("touch skip button")
device.touch(804,67,'DOWN_AND_UP')
mr.sleep(1)
 
print("input username and password")
device.touch(57,373,'DOWN_AND_UP')
mr.sleep(2)
device.type('zxw1234')
 
device.touch(152,480,'DOWN_AND_UP')
mr.sleep(2)
device.type('zxw123456')
mr.sleep(2)
 
print("touch login button")
device.touch(331,634,'DOWN_AND_UP')
 
 
print("takeSnapshot")
screenshot=device.takeSnapshot()
screenshot.writeToFile(r'D:\monkeyrunner\kyb.png','png')
 

注意事项

方法调用错误

AttributeError: type object 'com.android.monkeyrunner.XXXXX' has no attribute XXXXXX

检查调用的方法名是否写错,特别是注意区分大小写。

字符编码错误

SyntaxError: Non-ASCII character in file 'E:\monkeyrunner_script\kyb.py', but no encoding declared;

需要在代码顶部补充 # -- coding: utf-8 -- 或者去掉代码中的中文字符

Appium

Appium简介

Appium是一个开源测试自动化框架,可用于原生,混合和移动Web应用程序测试。 它使用WebDriver协议驱动iOS,Android和Windows应用程序。

Appium优势

  • 可以跨平台同时支持android、ios
  • 支持多种语言,java、python、php、Ruby等等
  • 不用为复杂的环境发愁
  • 如果你有selenium经验,直接上手。

Appium架构原理

  • Android(版本>4.3):UIAutomator,Android 4.3之后系统自带的UI自动化测试工具。
  • Android(版本≤4.3):Selendroid,基于Android Instrumentation框架实现的自动化测试工具。
  • ·iOS:UIAutomation(instruments框架里面的一个模板),iOS系统自带的UI自动化测试工具。

![https://sutune.oss-cn-shenzhen.aliyuncs.com/Appium 简介%26实践/mobile-test-automation-using-appium-ios-android.jpg](file:///C:\Users\林华的~1\AppData\Local\Temp\msohtmlclip1\01\clip_image002.jpg)

运行原理

我们的电脑(client)上运行自动化测试脚本,调用的是webdriver的接口,appium server接收到我们client上发送过来的命令后他会将这些命令转换为UIautomator认识的命令,然后由UIautomator来在设备上执行自动化。

Appium的架构原理如上图所示,由客户端(Appium Client)和服务器(Appium Server)两部分组成,客户端与服务器端通过JSON Wire Protocol进行通信。

Appium服务器

Appium服务器是Appium框架的核心。它是一个基于Node.js实现的HTTP服务器。Appium服务器的主要功能是接受从Appium客户端发起的连接,监听从客户端发送来的命令,将命令发送给bootstrap.jar(iOS手机为bootstrap.js)执行,并将命令的执行结果通过HTTP应答反馈给Appium客户端。

Bootstrap.jar。

Bootstrap.jar是在Android手机上运行的一个应用程序,它在手机上扮演TCP服务器的角色。当Appium服务器需要运行命令时,Appium服务器会与Bootstrap.jar建立TCP通信,并把命令发送给Bootstrap.jar;Bootstrap.jar负责运行测试命令。

Appium客户端。

它主要是指实现了Appium功能的WebDriver协议的客户端Library,它负责与Appium服务器建立连接,并将测试脚本的指令发送到Appium服务器。现有的客户端Library有多种语言的实现,包括Ruby、Python、Java、JavaScript(Node.js)、Object C、PHP和C#。Appium的测试是在这些Library的基础上进行开发的。

Appium组件

Appium Server

Appium Server就是Appium的服务端——一个web接口服务,使用Node.js实现。引用官网解释说明。

Appium Desktop

Appium Desktop是一款适用于Mac,Windows和Linux的开源应用程序,它以美观而灵活的用户界面为您提供Appium自动化服务器的强大功能。 它是几个Appium相关工具的组合:

  1. Appium Server的图形界面。 您可以设置选项,启动/停止服务器,查看日志等…您也不需要使用Node 的NPM来安装Appium,因为Node运行时与Appium Desktop捆绑在一起。
  2. 您可以使用Inspector查看应用程序的元素,获取有关它们的基本信息,并与它们进行基本的交互。

Appium GUI

Appium GUI是Appium desktop的前身。 这个也是把Appium server封装成了一个图形界面,降低使用门槛,如同最初的操作系统Dos都是敲命令,后面都是图形界面操作系统,如Windows系统。很多初学者对下面这个界面应该不陌生吧,这个就是Windows版本的Appium GUI界面。测试人员可以手动启动,配置相关server 服务,如果不用这个启动的话,需要命令启动服务。因为大部分教程都是基于这个GUI来讲解的,所以很多人一说Appium就认为是这个。

Appium Clients

因为Appium是一个C/S结构,有了服务端的肯定还有客户端,Appium Clients就是客户端,它会给服务端Appium Server发送请求会话来执行自动化任务。就像我们浏览器访问网页,浏览器是客户端,通过操作发送请求服务器来获取数据。我们可以使用不同的客户端浏览器(IE,Firefox,Chrome)访问一个网站。 Appium客户端可以使用不同的语言来实现,如Python,java等。具体详见下表:

Language/FrameworkGithub Repo and Installation Instructions
Rubyhttps://github.com/appium/ruby_lib
Pythonhttps://github.com/appium/python-client
Javahttps://github.com/appium/java-client
JavaScript (Node.js)https://github.com/admc/wd
Objective Chttps://github.com/appium/selenium-objective-c
PHPhttps://github.com/appium/php-client
C# (.NET)https://github.com/appium/appium-dotnet-driver
RobotFrameworkhttps://github.com/jollychang/robotframework-appiumlibrary

Appium-desktop

Appium-desktop主界面包含三个菜单Simple,Advanced、Presets

Capability

什么是Capability

desired capability的功能是配置Appium会话。他们告诉Appium服务器您想要自动化的平台和应用程序。

Desired Capabilities是一组设置的键值对的集合,其中键对应设置的名称,而值对应设置的值。(如:“platformName”: “Android”)Desired Capabilities主要用于通知Appium服务器建立需要的Session。

Session

Appium的客户端和服务端之间进行通信都必须在一个Session的上下文中进行。客户端在发起通信的时候首先会发送一个叫作“Desired Capabilities”的JSON对象给服务器。服务器收到该数据后,会创建一个session并将session的ID返回到客户端。之后客户端可以用该session的ID发送后续的命令。

常用Capability配置讲解

Capability官方完整文档

如果有了解过Capability的人会发现一个问题,其实他主要分成了三部分:公共部分、ios部分、android部分,如果你android想用ios的那是不可能的,so,老老实实去了解每个平台有哪些,他们的作用是什么。下面我们介绍一些公用常用的,红色标记的为常用的选项。

公用Capability

在这里插入图片描述

Android独有Capability

在这里插入图片描述

ios独有Capability

在这里插入图片描述

Capability启动App演示
New Session Window 会话建立
  • Automatic Server 本地AppiumServer服务
  • Custom Server:例如,如果要针对运行在网络中另一台计算机上的Appium服务器启动Inspector会话,这很有用。
  • Sauce Labs:如果您无法访问机器上的iOS模拟器,则可以利用Sauce Labs帐户在云中启动Appium会话。
  • TestObject:您还可以利用TestObject的真实设备云来进行真机测试。
  • headspin:使用远程设备来创建会话。
desired capability参数Josin
{
  "platformName": "Android",
  "platformVersion": "5.1.1",
  "deviceName": "127.0.0.1:62025",
  "appPackage": "com.tal.kaoyan",
  "appActivity": "com.tal.kaoyan.ui.activity.SplashActivity",
  "noReset": true
}

在这里插入图片描述

新的会话窗口允许您构造一组desired capabilities,用于启动Appium会话。您可以针对当前运行的Appium Desktop服务器(默认的)启动一个会话,或者您可以针对各种其他端点启动一个会话。

因为不需要使用Appium Desktop自己的服务器,您可以在不启动Appium Desktop服务器的情况下进入新的会话窗口。只需点击“File”(Windows / Linux)或“Appium”(Mac),然后选择“New Session…”,它将打开新的会话窗口,而不必启动本地服务器。在这种情况下,将禁用附加到本地服务器。

Inspector元素获取

启动成功之后就可以使用 Inspector来进行元素空间获取了。 注意:默认的元素定位有一些不准,需要切换到第二个坐标点定位选项后再切换回来才能准确定位。 在这里插入图片描述

appium元素定位

元素定位

与Web自动化测试一样,app自动化测试过程中最重要一个环节就是元素定位,只有准确定位到了元素才能进行相关元素的操作,如输入、点击、拖拽、滑动等。appium提供了许多元素定位的方法,如id定位、name定位、class定位、层级定位等等… 接下来将会给大家来实践运用这些定位技巧。

元素定位方式

  • id
  • name
  • class name
  • List定位
  • 相对定位
  • Xpath定位
  • H5页面元素定位
  • Uiautomator定位

UIAutomator

UIAutomator定位简介

UIAutomator元素定位是 Android 系统原生支持的定位方式,虽然与 xpath 类似,但比它更加好用,且支持元素全部属性定位.定位原理是通过android 自带的android uiautomator的类库去查找元素。 Appium元素定位方法其实也是基于Uiautomator来进行封装的。

使用方法 find_element_by_android_uiautomator() 可以运用UiAutomator元素定位。

定位方法

  • id定位
  • text定位
  • class name定位

id定位

id定位是根据元素的resource-id属性来进行定位,使用 UiSelector().resourceId()方法即可。

text定位

text定位就是根据元素的text属性值来进行定位,new UiSelector()

class name定位

与Appium class定位方式一样,也是根据元素的class属性来进行定位。

元素等待

思考

在自动化过程中,元素出现受网络环境,设备性能等多种因素影响。因此元素加载的时间可能不一致,从而会导致元素无法定位超时报错,但是实际上元素是正常加载了的,只是出现时间晚一点而已。那么如何解决这个问题呢?

元素等待作用

设置元素等待可以更加灵活的制定等待定位元素的时间,从而增强脚本的健壮性,提高执行效率。

元素等待类型

强制等待

设置固定的等待时间,使用sleep()方法即可实现

from time import sleep
#强制等待5秒
sleep(5)
隐式等待

隐式等待是针对全部元素设置的等待时间

driver.implicitly_wait(20)
显式等待

显式等待是针对某个元素来设置的等待时间。

方法WebDriverWait格式参数如下:

from selenium.webdriver.support.ui import WebDriverWait
 
WebDriverWait(driver, timeout, poll_frequency=0.5, ignored_exceptions=None)
driver : WebDriver
timeout : 最长超时时间,默认以秒为单位
poll_frequency : 休眠时间的间隔时间,默认为0.5秒
ignored_exceptions : 超时后的异常信息,默认情况下抛NoSuchElementException异常。

WebDriverWait()一般和until()或until_not()方法配合使用,另外,lambda提供了一个运行时动态创建函数的方法。

from selenium.webdriver.support.ui import WebDriverWait
WebDriverWait(driver,10).until(lambda x:x.find_element_by_id("elementID"))

Toast

Toast简介

Android中的Toast是一种简易的消息提示框。 当视图显示给用户,在应用程序中显示为浮动。和Dialog不一样的是,它永远不会获得焦点,无法被点击。

Toast

类的思想就是尽可能不引人注意,同时还向用户显示信息,希望他们看到。而且Toast显示的时间有限,一般3秒左右就消失了。因此使用传统的元素定位工具,我们是无法定位到Toast元素的(传说中低调奢华有内涵)。

Appium Toast内容获取

Appium 1.6.3开始支持识别Toast内容,主要是基于UiAutomator2,因此需要在Capablity配置如下参数:

desired_caps['automationName']='uiautomator2'

安装appium-uiautomator2-driver: 安装命令如下:

cnpm install appium-uiautomator2-driver

注意:Toast内容为中文时,顶部必须注释#
coding=utf-8 否则会因为编解码导致文字识别失败。

屏幕截图

应用背景

在实际自动化项目运行过程中,很多时候App可以会出现各种异常,为了更好的定位问题,除了捕捉日志我们还需要对运行时的设备状态来进行截屏。从而达到一种“有图有真相”的效果。

截图方法

方法1

save_screenshot() 该方法直接保存当前屏幕截图到当前脚本所在文件位置。

driver.save_screenshot('login.png')

方法2

get_screenshot_as_file(self, filename)

将截图保留到指定文件路径

driver.get_screenshot_as_file('./images/login.png')

实践案例

测试场景

在考研帮App登录页面输入用户名和密码之后截图,分别保存到当前文件和指定的文件路径。

代码实现

screenshot.py

from find_element.capability import driver
 
driver.find_element_by_id('com.tal.kaoyan:id/login_email_edittext').clear()
driver.find_element_by_id('com.tal.kaoyan:id/login_email_edittext').send_keys('55555')
 
driver.find_element_by_id('com.tal.kaoyan:id/login_password_edittext').send_keys('zxw2018')
 
driver.save_screenshot('login.png')
driver.get_screenshot_as_file('./images/login.png')
 
driver.find_element_by_id('com.tal.kaoyan:id/login_login_btn').click()

H5元素定位

问题思考

在混合开发的App中,经常会有内嵌的H5页面。那么这些H5页面元素该如何进行定位操作呢?

解决思路

针对这种场景直接使用前面所讲的方法来进行定位是行不通的,因为前面的都是基于Andriod原生控件进行元素定位,而Web网页是单独的B/S架构,两者的运行环境不同因此需要进行上下文(context)切换,然后对H5页面元素进行定位操作。

context

关于应用程序环境的全局信息的接口。
这是一个抽象类,其实现由Android系统提供。 它允许访问特定于应用程序的资源和类,以及对应用程序级操作的调用,如启动活动、广播和接收意图等。

通俗理解

​ 在程序中context我们可以理解为当前对象在程序中所处的一个环境。 比如前面提到的App一个界面是属于Activity类型,也就是Android界面环境,但是当访问内嵌的网页是属于另外一个环境(网页环境),两者处于不同的一个环境。

dr.fone app 内嵌网页地址:https://drfone.wondershare.com/backup.html

WebView

WebView是Android系统提供能显示网页的系统控件,它是一个特殊的View,同时它也是一个ViewGroup,可以有很多其他子View。

在Android 4.4以下(不包含4.4)系统WebView底层实现是采用WebKit(http://www.webkit.org/)内核,而在Android 4.4及其以上Google 采用了chromium(http://www.chromium.org/)作为系统WebView的底层内核支持。

Webview 调试模式检查与开启

基础检查方式

\1. 打开app对应的h5页面,在 chrome://inspect/#devices 地址中,检查是否显示对应的webview,如没有,则当前未开启调试模式。

\2. 在自动化脚本中,进入到对应的H5页面,打印输出当前context,如果一直显示为Natvie App,则webview未开启。

开启方式

在app中配置如下代码(在WebView类中调用静态方法setWebContentsDebuggingEnabled):

if (Build.VERSION.SDK_INT >=Build.VERSION_CODES.KITKAT) {  
 WebView.setWebContentsDebuggingEnabled(true);

注:此步骤,一般需要App开发人员开启。

抓取h5页面

switch_to.context 切换context

  1. 先进入到H5页面,然后切换到context,再进行相关元素定位操作。
  2. conetext切换:可以通过contexts()方法来获取到页面的所有context,然后切换到H5页面的context
  3. 在H5页面进行元素定位操作

滑动操作

在Appium中模拟用户滑动操作需要使用swipe方法

滑动主要分为:

  1. 水平滑动
  2. 垂直滑动
  3. 任意方向滑动

滑动轨迹图如下:

![https://sutune.oss-cn-shenzhen.aliyuncs.com/Appium 简介%26实践/chapter4/Swipe.PNG](file:///C:\Users\林华的~1\AppData\Local\Temp\msohtmlclip1\01\clip_image002.gif)

连续滑动操作

应用背景

滑动操作一般是两点之间的滑动,而实际使用过程中用户可能要进行一些多点连续滑动操作。如九宫格滑动操作,连续拖动图片移动等场景。那么在Appium中该如何模拟这类操作呢?

TouchAction

Touch Action包含一些列操作,比如按压、长按、点击、移动、暂停。由着些不同操作可以组成一套动作。使用TochAction需要先导入对应的模块

from appium.webdriver.common.touch_action import TouchAction

按压

方法:press() 开始按压一个元素或坐标点(x,y)。通过手指按压手机屏幕的某个位置。 press也可以接收屏幕的坐标(x,y)。

press(self, el=None, x=None, y=None)
 
TouchAction(driver).press(x=0,y=308)

长按

方法:longPress() 开始按压一个元素或坐标点(x,y)。 相比press()方法,longPress()多了一个入参,既然长按,得有按的时间吧。duration以毫秒为单位。1000表示按一秒钟。其用法与press()方法相同。

long_press(self, el=None, x=None, y=None, duration=1000)

点击

方法:tap() 对一个元素或控件执行点击操作。用法参考press()。

tap(self, element=None, x=None, y=None, count=1)

移动

方法:move_to() 将指针从上一个点移动到指定的元素或点。

move_to(self, el=None, x=None, y=None)

注意:

移动到目位置有时是算绝对坐标点,有时是基于前面一个坐标点的偏移量,这个要结合具体App来实践。

暂停

方法:Wait()

wait(self, ms=0)

暂停脚本的执行,单位为毫秒。

释放

方法release() 结束的行动取消屏幕上的指针。

release(self)

执行

perform() 执行的操作发送到服务器的命令操作。

perform(self)

多点触控操作

MultiAction

MultiAction 是多点触控的类,可以模拟用户多点操作。主要包含 add()perform() 两个方法, MultiAction可以结合前面所学的 ActionTouch可以模拟出用户的多个手指滑动的操作效果;

from appium.webdriver.common.multi_action import MultiAction
from appium.webdriver.common.touch_action import TouchAction

加载:

方法add(self, *touch_actions)将TouchAction对象添加到MultiAction中,稍后再执行。

参数:
  • touch_actions - 一个或多个TouchAction对象,描述一个手指要执行的动作链
用法
a1 = TouchAction(driver)
a1.press(el1).move_to(el2).release()
 
a2 = TouchAction(driver)
a2.press(el2).move_to(el1).release()
 
MultiAction(driver).add(a1, a2)

执行

perform(self) 执行存储在对象中的操作。

用法
a1 = TouchAction(driver)
a1.press(el1).move_to(el2).release()
 
a2 = TouchAction(driver)
a2.press(el2).move_to(el1).release()
 
MultiAction(driver).add(a1, a2).perform()

Ps:是不是有点类似Python里面的多线程和多进程的使用。

appium进阶

yaml概述

yaml简介

正如YAML所表示的YAML Ain’t Markup Language,YAML 是一种简洁的非标记语言。YAML以数据为中心,使用空白,缩进,分行组织数据,从而使得表示更加简洁易读。

由于实现简单,解析成本很低,YAML特别适合在脚本语言中使用。列一下现有的语言实现:Ruby,Java,Perl,Python,PHP,JavaScript等。

YAML

是专门用来写配置文件的语言,非常简洁和强大,远比 JSON 格式方便。

语法特点

  • 大小写敏感
  • 使用缩进表示层级关系
  • 缩进时不允许使用Tab键,只允许使用空格。
  • 缩进的空格数目不重要,只要相同层级的元素左侧对齐即可

yaml数据类型详解

支持数据类型

  1. 纯量(scalars):单个的、不可再分的值
  2. 数组:一组按次序排列的值,又称为序列(sequence) / 列表(list)
  3. 对象:键值对的集合,又称为映射(mapping)/ 哈希(hashes) / 字典(dictionary)

纯量

数据最小的单位,不可以再分割。类似于Python中单个变量

flag

list数组

与Python的list数组结构类似,数组元素使用“-”开头,也可以根据缩进进行数组嵌套。

- Jack
- Harry
- Sunny
 
# 也可以写成一行
[Jack,Harry,Sunny]

对应到python的list写法如下:

['Jack','Harry','Sunny']

扩展学习:Python数据类型视频教程

对象

对象的一组键值对,使用冒号结构表示。类似Python中的字典数据结构。

platformName: Android
platformVersion: 6.0.1
 
# Yaml 也允许另一种写法,将所有键值对写成一个行内对象。
{platformName: Android,platformVersion: 6.0.1}

注意:冒号后面一定要有空格!对应到python字典的写法如下:

{'platformName': 'Android', 'platformVersion': '6.0.1'}

数据嵌套

yaml数据嵌套表示可以将上面的各类数据根据实际场景进行组合嵌套。

yaml数据操作

数据读取

load方法

load(stream, Loader=Loader) 解析文件流中的第一个YAML文档并生成相应的Python对象。

数据修改

如果想改变某个数据,可以使用如下方法:

data['name']='51zxw'
print(data['name'])

注意:此处只是变量类型的数据变更,不会真正修改到yaml配置表中的数据。

数据转化

方法:dump()可以将Python对象序列化成YAML流。如果stream为None,则返回生成的字符串。

日志概述

日志作用

不管是在项目开发还是测试过程中,项目运行一旦出现问题日志信息就非常重要了。日志是定位问题的重要手段,就像侦探人员要根据现场留下的线索来推断案情。

日志级别

脚本运行会有很多的情况,比如调试信息、报错异常信息等。日志要根据这些不同的情况来继续分级管理,不然对于排查问题的筛选会有比较大的干扰。 。日志一般定位的级别如下:

级别何时使用
DEBUG调试信息,也是最详细的日志信息。
INFO证明事情按预期工作。
WARNING表明发生了一些意外,或者不久的将来会发生问题(如‘磁盘满了’)。软件还是在正常工作。
ERROR由于更严重的问题,软件已不能执行一些功能了。
CRITICAL严重错误,表明软件已不能继续运行了。

首先我们日志需要按照info、debug、error等级别来进行区分的。当然这个级别可以自己去设置。在一般的情况下我们普通的输出我们直接用info类型,调试的时候用debug类型,如果预计有错误时那么我们就需要用error类型的日志,一般情况去info级别最为合适。

日志格式

日志格式化是为了提高日志的可阅读性,比如:时间+模块+行数+日志具体信息 的内容格式。如果日志信息杂乱无章的全部输出来,这样也不利于定位问题。如下所示就是日志格式化输出,非常便于阅读查看。

2018-01-10 18:02:35,633 backup.py[line:18] INFO ============test backup================
2018-01-10 18:02:39,253 backup.py[line:20] INFO click backup button
2018-01-10 18:02:54,025 backup.py[line:23] INFO click next button
2018-01-10 18:03:09,280 common_fun.py[line:83] INFO Start send Email..
2018-01-10 18:03:11,840 common_fun.py[line:91] INFO Send Email finish!
2018-01-10 18:03:13,305 common_fun.py[line:168] INFO get backup screenshot
2018-01-10 19:36:00,238 backup.py[line:17] INFO ============test backup================
2018-01-10 19:36:04,530 backup.py[line:19] INFO click backup button
2018-01-10 19:37:20,107 backup.py[line:17] INFO ============test 

日志位置

一个项目中会有很多的日志采集点,而日志采集点必须结合业务属性来设置。比如在登录代码执行前可以插入“准备登录…”日志信息,如果登录完成之后,再设置登录的提示日志就会给人造成误解,无法判断到底是登录之前的问题还是登录之后的问题,因此日志采集点的位置很重要。

logging模块

简介

Python的logging模块提供了通用的日志系统,这个模块提供不同的日志级别,并可以采用不同的方式记录日志,比如文件,HTTP GET/POST,SMTP,Socket等,甚至可以自己实现方式记录日志。

#导入logging模块
import logging

logging模块官方文档

logging构成

logging模块包括logger,Handler,Filter,Formatter四个部分。

  • Logger 记录器,用于设置日志采集。
  • Handler 处理器,将日志记录发送至合适的路径。
  • Filter 过滤器,提供了更好的粒度控制,它可以决定输出哪些日志记录。
  • Formatter 格式化器,指明了最终输出中日志的格式。

Logger 记录器

Logger是一个树形层级结构,在使用接口debug,info,warn,error,critical;使用之前必须创建Logger实例,即创建一个记录器,如果没有显式的进行创建,则默认创建一个root logger,并应用默认的日志级别(WARN),Handler和Formatter。

方法:

basicConfig(**kwargs) 为日志记录系统做基本配置。

部分参数

filename 指定日志文件名称

filemode 指定打开文件的模式,如果指定了filename(如果文件模式未指定,则默认为’a)

Tips:文件读写模式

  • w 以写方式打开,
  • W 文件若存在,首先要清空,然后(重新)创建
  • a 以追加模式打开 (从 EOF 开始, 必要时创建新文件)
  • r+ 以读写模式打开
  • w+ 以读写模式打开 (参见 w )
  • a+ 以读写模式打开 (参见 a )

format 为处理程序使用指定的格式字符串。

datefmt 使用指定的日期/时间格式。样式如果指定了格式字符串,则使用它来指定 格式字符串的类型.

level 将根记录器级别设置为指定级别。

Handler 处理器

Handler 处理器,将日志记录发送至合适的路径,Handler处理器类型有很多种,比较常用的有三个:

1.StreamHandler

将日志记录输出发送到诸如sys.stdout,sys.stderr或任何类似文件流的对象。上面例子就是输出到控制台

2.FileHandler

将日志记录输出发送到磁盘文件。 它继承了StreamHandler的输出功能。

logging.basicConfig(filename='runlog.log',level=logging.DEBUG)
 

3.NullHandler

不做任何格式化或输出。 它本质上是一个开发人员使用的“无操作”处理程序。

Filter 过滤器

Handlers和Loggers可以使用Filters来完成比级别更复杂的过滤。

Formatter

使用Formatter对象设置日志信息最后的规则、结构和内容,默认的时间格式为%Y-%m-%d %H:%M:%S。

格式描述
%(levelno)s打印日志级别的数值
%(levelname)s打印日志级别名称
%(pathname)s打印当前执行程序的路径
%(filename)s打印当前执行程序名称
%(funcName)s打印日志的当前函数
%(lineno)d打印日志的当前行号
%(asctime)s打印日志的时间
%(thread)d打印线程id
%(threadName)s打印线程名称
%(process)d打印进程ID
%(message)s打印日志信息

使用方法:

logging.basicConfig(filename='runlog.log',level=logging.DEBUG,
                  format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s')
                  

输出结果:

2018-04-19 17:25:04,679 logging_test.py[line:12] DEBUG debug info
2018-04-19 17:25:04,680 logging_test.py[line:13] INFO hello 51zxw 2020
2018-04-19 17:25:04,680 logging_test.py[line:14] WARNING waning info
2018-04-19 17:25:04,680 logging_test.py[line:15] ERROR error info
2018-04-19 17:25:04,680 logging_test.py[line:16] CRITICAL critical info

PageObject+unittest

案例分析

上面的脚本看似都比较完善,有了log采集,参数配置、启动时页面元素自动检测。但是也存在一些不足之处:

  • 公共模块和业务模块混合在一起显得代码冗余等
  • 测试场景单一(如果要实现如下测试场景该怎么办?)
  • 元素定位属性和代码混杂在一起

以上这些都是需要优化的地方。

测试场景操作步骤预期结果
多账号登录不同的用户名密码来进行登录能够正常登录
异常登录用户名或者密码错误、或者为空进行登录,登录失败,同时界面要给出相应的提示
注册点击注册,然后进行注册信息填写能够注册成功

重构优化思路

  • 将一些公共的内容(如:check_updateBtn,check_skipBtn,capability)抽离出来。
  • 元素定位方法和元素属性值与业务代码分离
  • 登录功能模块封装为一个独立的模块
  • 使用unittest进行用例综合管理

Page Object

Page Object是Selenium自动化测试项目开发实践的最佳设计模式之一,通过对界面元素的封装减少冗余代码,同时在后期维护中,若元素定位发生变化,只需要调整页面元素封装的代码,提高测试用例的可维护性。

补充资料:

Python类与对象视频教程

Selenium PageObject 视频讲解

Python可变数量参数视频讲解

By方式元素定位视频讲解

Selenium自动化第六章-unittest单元测试框架

Appium 并发测试

启动多个Appium服务

前面课程只是启动了单个appium服务,只能控制单台设备。如果需要针对多台设备测试那么该如何处理?

首先看下面两个启动appium服务案例。

启动appium服务1

C:\Users\Shuqing>appium -p 4723
[Appium] Welcome to Appium v1.7.2
[Appium] Appium REST http interface listener started on 0.0.0.0:4723
 
 

启动appium 服务2

C:\Users\Shuqing>appium -p 4725
[Appium] Welcome to Appium v1.7.2
[Appium] Non-default server args:
[Appium]   port: 4725
[Appium] Appium REST http interface listener started on 0.0.0.0:4725
 

上面案例我们启动了2个不同的appium服务器,他们通过不同的端口来区分不同的服务;如同百米赛跑要给不同的运动员安排不同的赛道,每个运动员也只能在自己指定的赛道进行比赛。

Appium常用参数

参数默认值含义
-U, --udidnull连接物理设备的唯一设备标识符
-a, --address0.0.0.0监听的 ip 地址
-p, --port4723监听的端口
-bp, --bootstrap-port4724连接Android设备的端口号(Android-only)
-g, --lognull将日志输出到指定文件
–no-resetfalsesession 之间不重置应用状态
–session-overridefalse允许 session 被覆盖 (冲突的话)
–app-activitynull打开Android应用时,启动的 Activity(Android-only) 的名字
–appnull本地绝对路径_或_远程 http URL 所指向的一个安装包

更多参数请输入命令: appium -h

Python启动Appium 服务

bp端口(
–bootstrap-port)是appium和设备之间通信的端口,如果不指定到时无法操作多台设备运行脚本。

代码实现

首先我们使用Python脚本启动单个appium服务:

  • host:127.0.0.1
  • port:4723

multi_appium.py

import subprocess
from time import ctime
 
def appium_start(host,port):
    '''启动appium server'''
    bootstrap_port = str(port + 1)
    cmd = 'start /b appium -a ' + host + ' -p ' + str(port) + ' -bp ' + str(bootstrap_port)
 
    print('%s at %s' %(cmd,ctime()))
    subprocess.Popen(cmd, shell=True,stdout=open('./appium_log/'+str(port)+'.log','a'),stderr=subprocess.STDOUT)
 
 
if __name__ == '__main__':
    host = '127.0.0.1'
    port=4723
    appium_start(host,port)

启动校验

启动后我们需要校验服务是否启动成功,校验方法如下:

  1. 首先查看有没有生成对应的log文件,查看log里面的内容。
  2. 使用如下命令来查看
netstat -ano |findstr 端口号

netstat 命令解释

netstat命令是一个监控TCP/IP网络的非常有用的工具,它可以显示路由表、实际的网络连接以及每一个网络接口设备的状态信息。输入 netstat -ano 回车.可以查看本机开放的全部端口;输入命令 netstat -h可以查看全部参数含义。

C:\Users\Shuqing>netstat -ano |findstr "4723"
  TCP    127.0.0.1:4723         0.0.0.0:0              LISTENING       8224

关闭Appium服务

关闭进程有2种方式,具体如下:

\1. 通过netstat命令找到对应的Appium进程pid然后可以在系统任务管理器去关闭进程;

win7系统任务管理器PID显示

  1. 使用如下命令来关闭:
taskkill -f -pid appium进程id

多个appium服务启动

多个appium服务启动非常简单,只需在执行环境使用循环调用即可。

if __name__ == '__main__':
    host = '127.0.0.1'
    for i in range(2):
        port=4723+2*i
        appium_start(host,port)

Appium端口检测

端口检测

端口检测需要使用到socket模块来校验端口是否被占用。

什么是socket?

网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。建立网络通信连接至少要一对端口号(socket)。

socket本质是编程接口(API),对TCP/IP的封装,TCP/IP也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口;HTTP是轿车,提供了封装或者显示数据的具体形式;Socket是发动机,提供了网络通信的能力。

例如当你用浏览器打开我要自学网主页时,你的浏览器会创建一个socket并命令它去连接 自学网的服务器主机,服务器也对客户端的请求创建一个socket进行监听。两端使用各自的socket来发送和接收信息。在socket通信的时候,每个socket都被绑定到一个特定的IP地址和端口。

补充资料: 网络工程师视频教程

©️2020 CSDN 皮肤主题: 创作都市 设计师:CSDN官方博客 返回首页