Appium - 自动化测试框架 - 工作原理环境搭建

Posted 测试小鬼

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Appium - 自动化测试框架 - 工作原理环境搭建相关的知识,希望对你有一定的参考价值。

在这里,我还给大家推荐一套app自动化测试的视频,比文字内容更容易理解!

python+Appium自动化测试框架【项目实战合集】,轻松掌握app高级自动化测试_哔哩哔哩_bilibilipython+Appium自动化测试框架【项目实战合集】,轻松掌握app高级自动化测试共计12条视频,包括:1、App环境搭建、2、App自动化测试原理、3、App自动化之Desired Capabilites-Appium自动化配置项等,UP主更多精彩视频,请关注UP账号。https://www.bilibili.com/video/BV1uY411W7WL/?spm_id_from=333.999.0.0

前言

Appium是移动端的UI自动化测试框架,基于C/S模式,特点是支持跨平台(安卓,ios),支持多语言(对java,python都有支持的API)。本文系博主对于该框架的部分学习记录。

一、什么是Appium

Appium是一个开源、跨平台的测试框架,可以用来测试原生及混合的移动端应用。Appium支持IOS、android及FirefoxOS平台。Appium使用WebDriver的json wire协议,来驱动Apple系统的UIAutomation库、Android系统的UIAutomator框架。Appium对IOS系统的支持得益于Dan Cuellar’s对于IOS自动化的研究。Appium也集成了Selendroid,来支持老android版本。

Appium支持Selenium WebDriver支持的所有语言,如java、Object-C、javascriptphp、Python、Ruby、C#、Clojure,或者Perl语言,更可以使用Selenium WebDriver的Api。Appium支持任何一种测试框架。如果只使用Apple的UIAutomation,我们只能用javascript来编写测试用例,而且只能用Instruction来运行测试用例。同样,如果只使用Google的UIAutomation,我们就只能用java来编写测试用例。Appium实现了真正的跨平台自动化测试。

appium选择了client-server的设计模式。只要client能够发送http请求给server,那么的话client用什么语言来实现都是可以的,这就是appium及webdriver如何做到支持多语言的;

下面这段介绍来自于appium的官网。

Appium is an open-source tool you can use to automate mobile native, mobile web, and mobile hybrid applications on iOS and Android platforms. “Mobile native apps” are those written using the iOS or Android SDKs. “Mobile web apps” are web apps accessed using a mobile browser (Appium supports Safari on iOS and Chrome on Android). “Mobile hybrid apps” have a native wrapper around a “webview” – a native control that enables interaction with web content. Projects like Phonegap, for example, make it easy to build apps using web technologies that are then bundled into a native wrapper – these are hybrid apps. Importantly, Appium is “cross-platform”: it allows you to write tests against multiple platforms (iOS, Android), using the same API. This enables a large or total amount of code reuse between iOS and Android testsuites.

二、搭建Appium+Python自动化测试环境

1、安装JDK并配置JDK的环境变量。

(1) JDK的下载

下载地址:
https://www.oracle.com/java/technologies/javase-downloads.html

下载版本选择主流的jdk1.8的版本:jdk-8u241-windows-x64.exe

(2) 配置JDK的环境变量:

我的电脑右键属性-->高级系统设置-->高级-->环境变量-->系统变量:

1、新建系统变量:

变量名:JAVA_HOME

变量值:C:\\Program Files\\Java\\jdk1.8.0_211 (这里是jdk的实际安装路径)

2、新建系统变量:

变量名:CLASSPATH

变量值:.;%JAVA_HOME%\\lib;%JAVA_HOME%\\lib\\tools.jar;%JAVA_HOME%\\lib\\dt.jar; (前面有一点和冒号不能少)

3、编辑PATH变量,在PATH的最后面添加:

%JAVA_HOME%\\bin;%JAVA_HOME%\\jre\\bin;(PATH中原来的路径不要去掉哦)

4、验证是否安装并配置成功:

在dos中输入javac和java -version验证。(分别出现一堆英文和jdk的版本信息则说明安装配置成功!)

如果基础太弱请点击:
https://blog.csdn.net/pengjiangchun/article/details/105419683 里面有很详细的步骤和截图!

2、安装SDK并配置SDK的环境变量。

(1) SDK的下载

下载地址:
http://tools.android-studio.org/index.php/sdk/

下载版本选择:
android-sdk_r24.4.1-windows.zip

(2) SDK的安装

进入D:\\android-sdk-windows目录,双击SDK Manager.exe下载对应的包:

a.以下三个Android工具包必须安装:只需要下载最新的版本就行了。

b.Extras(附加设备)

c.安卓版本:安装和模拟器安卓版本一致的SDK。现在android 5开发的场景多一些

夜神模拟器查看Android版本:设置左边的三横->关于我们->Android版本

(3) 配置SDK的环境变量

我的电脑右键属性-->高级系统设置-->高级-->环境变量-->系统变量:

1、新建:

变量名:ANDROID_HOME

变量值:D:\\android-sdk-windows (SDK的实际安装路径)

2、编辑PATH,在最后面添加:

%ANDROID_HOME%\\platform-tools;%ANDROID_HOME%\\tools;%ANDROID_HOME%\\build-tools\\29.0.3;

(如果原来PATH路径最后不是;则加一个;再添加上面的内容)

3、验证是否安装并配置成功:

在dos中输入adb验证。在最上面出现Android Debug Bridge version版本信息,如下图表示成功!

3、安装夜神模拟器并在模拟器上安装被测app

(1) 夜神模拟器的下载

下载地址:https://www.yeshen.com/

版本选择:最新版

(2) 夜神模拟器的安装

下一步下一步傻瓜式安装。

(3) 被测app的安装

把apk包直接拖拽到夜神模拟中安装

(4) 设置模拟器/真机的环境

1.启用设备的开发者选项,启动调试功能。

夜神模拟器:设置->多次点击版本号直到出现提示【开发者选项】->返回上一步能看到【开发者选项】->USB调试。

2.输入命令前:因为SDK下的adb[在SDK安装目录的platform-tools目录下]和模拟器的nox_adb[在夜神安装目录的bin目录下]版本不一致,所以需要把SDK路径下的abd.exe复制到模拟器的bin路径下,重命名为nox_adb.exe,原来的nox_adb.exe先备份。

4.安装和配置Appium

(1) 下载和安装appium-desktop。

下载地址:(强烈建议使用迅雷下载)

https://github.com/appium/appium-desktop/releases

(2) 打开appium输入:127.0.0.1和4723登录,如下图:

如果此端口被占用:可以使用此命令检查端口是否被占用:netstat -ano | findstr 4723

(3) 配置Appium检查器:

A.Appium右上角有三个选项分别为:

start inspector session 开始检查回话(点击它)

Get Raw Logs 获得原生日志

Stop Server 停止服务

B.点击Automatic Server(自动化服务)

在Desired Capabilities选项中输入如下内容,如图:

deviceName:设备名称

获取方式:通过adb devices获取。输入adb devices后出现

值为:127.0.0.1:62001

platformName:操作系统名称

可填写:Android和IOS

值为:Android

platformVersion:操作系统版本

查看天天模拟器的anroid版本获取得到。

夜神模拟器查看Android版本:设置左边的三横->关于我们->Android版本

appPackage:包名

通过aapt.exe获取:aapt dump badging apk包的路径。

值为:找到package后面的值,一般在第一行。如:tv.danmaku.bili

appActivity:activity程序主入口

通过aapt.exe获取:aapt dump badging apk包的路径,

找到launchable-activity后面的值,如:
tv.danmaku.bili.ui.splash.SplashActivity

第一种可以取全部的值,第二种也可以只取包名以后的内容:

第一种值为:
tv.danmaku.bili.ui.splash.SplashActivity

第二种值为:.ui.splash.SplashActivity (注意:前面有个点不能省略)

保存后点击"Start Session"如出现:unkown... 错误,是因为模拟器中没有安装apk包。

如果正常在模拟器里启动app则表示appium自动化测试环境搭建成功!

三、工作原理

Appium的构成

  • Appium 客户端 -- java写的,运行在PC上,开启后就可以提供Appium服务。
  • Appium 服务器 -- Appium Server,运行在PC上,监听端口,发送指令到移动设备。
  • 安卓模拟设备(Android SDK)-- 运行在设备上,用来执行自动化操作。

Appium工作流程(Android为例)

  • 测试脚本调用Appium Server提供的API,发送请求到Appium Server
  • Appium Server接收到脚本的请求后,发送指令到手机设备
  • 手机设备会安装一个Bootstrap.jar,作为中间件,会开启一个基于Appium服务的Socket,监听4724端口,将Appium Server发送的指令转为UIAutomator指令
  • UIAutomator指令执行操作后,响应原路返回

Appium源码分析(Python为例)

我们打开Appium客户端后,会开启Appium Server服务,默认会去监听4723端口,此时,脚本会通过该端口去和Appium Server通信,这个通信过程本质上是脚本发送 HTTP request请求到Appium Server。由于我们的目的是要通过脚本去操作手机设备,所以需要把设备的一些信息告诉给Appium Server,则需要传入个字典参数,即 desired Capabilities,以下是该参数的可取值表。

当调用quit方法时,会关闭session所关联的窗口。需要获取实战视频可以私信我,发送555既可!

Appium自动化测试框架

Appium自动化测试框架


环境搭建

  • JDK环境安装(不介绍,自己百度)
  • 安卓SDK环境安装

百度网盘下载链接,密码: kgwb

  • 安卓SDK可以直接从下面的镜像连接进行下载
http://110.40.155.17/download/

把SDK下的这两个目录位置加入PATH环境变量即可

D:\\SDK\\androidsdk\\platform-tools
D:\\SDK\\androidsdk\\tools

  • 安装Appium-DeskTop
  • 手机模拟器下载夜神模拟器

为了防止可能存在的SDK冲突,建议将夜神模拟器安装目录下的nx-adb.exe替换为我们安装的SDK目录的adb.exe


adb

ADB全名Android Debug Bridge,是一个调试工具

构成和原理

  • Client端 发送adb命令的电脑
  • Daemon守护进程,安卓手机中接受adb命令的
  • Server端 手机中管理通信的


工作原理

  • client发送命令给server
  • server将命令交给Daemon
  • daemon执行命令
  • 执行结果返回给server端
  • 执行结果发送给client端

abd工具可以在电脑通过终端命令来操作安卓手机/模拟器


连接

  • 连接某台手机或者模拟器(夜神模拟器程序暴露连接端口为620001)
adb connect 127.0.0,1:62001
  • adb devices : 检测到连接到电脑的安卓设备

包名,界面名

自动化测试需要通过代码的形式告诉手机测试那个应用程序的哪一个界面,所以需要通过某种方式定位到某个应用程序的某个页面。

  • 包名(package):决定程序的唯一性—可以用来定位到某个应用程序
  • 界面名(activity): 一个界面名通常对应一个界面,界面名又被叫做启动名

获取包名和界面名的命令:

  • Mac/Linux
adb shell dumpsys window windows | grep mFocusedApp
  • Windows
adb shell dumpsys window windows | findstr mFocusedApp

获取当前手机上打开正在显示的那个应用程序的包名和界面名

mFocusedApp=AppWindowToken43fda26 token=Token51a168 ActivityRecordffecc8b u0 com.android.settings/.Settings t3
  • 包名: com.android.settings
  • 界面名(启动名):.Settings


文件传输

  • 发送数据到手机
adb push 电脑文件路径 手机文件夹路径
‪C:\\Users\\zdh\\Desktop\\stu.sql
  • 将某个.txt文件发送到手机的SDK卡,SDK卡的根目录名固定为/sdcard



  • 从手机获得数据
adb pull 手机的文件路径 电脑的文件夹路径

例如:

adb pull /sdcard/stu.sql C:\\Users\\hhh

获取APP启动时间

adb shell am start -W 包名/启动名(界面名)
  • 命令作用: 启动对应的程序,并进入指定的界面

例如: 我们点击设置程序,看看它的启动时间(我们只需要执行下面的命令,该命令会发送给对应的手机和模拟器,然后对应会去打开设置应用程序,记录相关时间参数后,返回给我们)

adb shell am start -W com.android.settings/.Settings


参数解释:

  • ThisTime: 该界面(activity)启动耗时(毫秒)
  • TotalTime:应用自身启动耗时=ThisTime+应用application等资源启动时间(毫秒)
  • WaitTime:系统启动应用耗时=TotalTime+系统资源启动时间(毫秒)


获取手机日志

adb logcat
  • 使用上面命令后,会实时监控手机运行时输出的日志信息
  • 在调试程序的时候,通过实时监控日志信息,可以找到错误日志,然后记录下来

安装和卸载APP

安装app到手机
adb install 路径/xx,apk 
卸载手机上的app,需要指定包名--获取应用程序包名的方法上面给出了
adb uninstall 包名 

进入到安卓手机内部的Linux系统命令行

adb shell

启动和停止adb服务端

  • 启动adb服务端,出bug时使用可以重启服务器,先关闭再启动
adb start-server
  • 停止adb服务端
adb kill-server

查看命令帮助

adb --help

其他命令


Appium


save as Preset是保存当前预设配置


inspector工具



填写完毕后,先保存配置,然后点击start session开启会话即可


元素探测

appium提供的元素探测

原生的探测工具


包名和类名


查询当前聚焦的页面类名

adb shell dumpsys window windows | findstr mFocusedApp

aapt命令

需要先进入sdk安装目录的build-tools目录下

  • 查询包名
aapt dump badging 应用apk的路径 | findstr package
  • 查询类名
aapt dump badging 应用apk的路径 | findstr launchable-activity


APP类型



APP布局和控件



JAVA SDK

  • 引入依赖
        <dependency>
            <groupId>io.appium</groupId>
            <artifactId>java-client</artifactId>
            <version>7.6.0</version>
        </dependency>
  • 入门案例
    @Test
    public void test() throws MalformedURLException 
        //1.创建配置对象
        DesiredCapabilities desiredCapabilities=new DesiredCapabilities();
        //2.添加配置
        //deviceName:找到测试的设备
        desiredCapabilities.setCapability("deviceName","127.0.0.1:62001");
        //platformName:测试平台
        desiredCapabilities.setCapability("platformName","Android");
        //appPackage:测试app包名
        desiredCapabilities.setCapability("appPackage","com.android.browser");
        //appActivity:测试App启动入口
        desiredCapabilities.setCapability("appActivity",".BrowserActivity");

        //3.创建驱动
        //appium的通讯地址和配置对象
        AndroidDriver<WebElement> androidDriver=new AndroidDriver<WebElement>(new URL("http://127.0.0.1:4723/wd/hub"),desiredCapabilities);
    

adb shell dumpsys window windows | findStr mFocusedApp: 命令可以获取到我们要测试app的包名和对应的界面名


元素定位和元素操作

这里通过测试登录qq为案例

  • 建议通过原生SDK拍摄快照的方式来定位元素的id,这样会快很多

public class TestOne 
    @Test
    public void test() throws MalformedURLException, InterruptedException 
        //1.准备,并打开qq程序
        AndroidDriver<WebElement> androidDriver = prepare("com.tencent.mobileqq", ".activity.LoginActivity");
         //2.定位然后操作元素
        //点击同意按钮
        androidDriver.findElementById("com.tencent.mobileqq:id/dialogRightBtn").click();
        //等待程序更新--休眠10s
        Thread.sleep(15000);
        System.out.println("点击登录按钮");
        //点击登录按钮
        TouchAction touchAction=new TouchAction(androidDriver);
        touchAction.tap(PointOption.point(500,1470)).release().perform();
        //等待页面刷新
        Thread.sleep(3000);
        System.out.println("输入账号和密码");
        //输入qq账号
        androidDriver.findElementByAccessibilityId("请输入QQ号码或手机或邮箱").sendKeys("xxxx");
        //输入qq密码
        androidDriver.findElementById("com.tencent.mobileqq:id/password").sendKeys("xxx");
        //点击登录
        androidDriver.findElementByAccessibilityId("登 录").click();
        Thread.sleep(10000);
        //退出
        androidDriver.quit();
    

    public AndroidDriver<WebElement> prepare(String appPackage,String appActivity) throws MalformedURLException 
        //1.创建配置对象
        DesiredCapabilities desiredCapabilities=new DesiredCapabilities();
        //2.添加配置
        //deviceName:找到测试的设备
        desiredCapabilities.setCapability("deviceName","127.0.0.1:62001");
        //platformName:测试平台
        desiredCapabilities.setCapability("platformName","Android");
        //appPackage:测试app包名
        desiredCapabilities.setCapability("appPackage",appPackage);
        //appActivity:测试App启动入口
        desiredCapabilities.setCapability("appActivity",appActivity);
        //更换新引擎--uiautomator2解决输入框输入不了数据
        desiredCapabilities.setCapability("automationName","uiautomator2");

        //3.创建驱动
        //appium的通讯地址和配置对象
        return new AndroidDriver<WebElement>(new URL("http://127.0.0.1:4723/wd/hub"),desiredCapabilities);
    




配合Testng框架使用

自动化测试提速之利剑——TestNG

TestNG Hello World入门示例


Appium自动化原理


对于安卓应用来说,Appium会往对应安卓手机上推送一个Bootstrap.jar并运行它,当我们自动化测试程序向appium发送请求时,appium向Boostrap.jar发送请求,由Bootstrap.jar转发请求到安卓手机底层的自动化测试框架UIAutomator。

再由底至上,将测试结果最终返回给我们的测试程序。


初始化流程

通过appium初始化日志分析得到

  • 获取配置相关参数

  • 相关环境检查—jdk版本,连接的设备,adb配置,设备的sdk版本
  • 检查对应的应用程序是否安装,并且判断设备是否可以正常连接
  • 将自动辅助程序appium.setting推送到手机端,如果已经安装就不管了
  • 获取手机相关信息,屏幕尺寸,品牌等
  • 检查对应包名是否已经安装好了,如果安装好了,如果该应用程序在执行,会停止掉
  • 清空应用程序数据—shell pm clear 包名
  • 设置端口转发,推送Bootstrap.jat包到手机端,然后启动
  • 启动应用程序

元素定位

ID定位

//如果resource-id唯一,那么使用下面这个方法就行
//如果存在多个元素resource-id相同,那么下面api默认选择第一个
androidDriver.findElementById();
//如果存在多个元素resource-id相同,使用下面api---返回一个list
androidDriver.findElementsById();


text定位

  • Appium 1.5之前版本支持By.name方式
androidDriver.findElement(By.name(""));
  • 最新版本Appium不再支持此API,需要使用UIAutomator原生自动化引擎
 androidDriver.findElementByAndroidUIAutomator("new UiSelector().text('登录')");


className定位

根据class属性去找元素,一般在页面中很多元素的class属性都是一致的,所以这种方式基本不用。


xpath定位

  • xpath有相对定位和绝对定位,注意区分
        //使用相对定位---//开头
        androidDriver.findElementByXPath("//android.widget.Button[@text='登录']").click();


accessibility id定位

在UIAutomatorViewer并没有此属性,对应是content-desc属性

        androidDriver.findElementByAccessibilityId("登 录").click();


测试前不清除应用程序数据

        //不清除应用数据启动测试
        desiredCapabilities.setCapability("noReset","true");

元素等待


强制等待

设置固定等待时间,即便不需要等待即可定位到元素,依然要求进行等待

Thread.sleep();

隐式等待

针对全局元素设置等待时间,服务端(Appium)会在特定的超时时间内重试多次寻找控件

        androidDriver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);

隐式等待就是在设置的时间范围内整个页面元素加载出来,然后再轮询页面元素直到寻找成功,如果超出时间后仍然未找到元素则继续往下面执行。

同时要注意的是,driver设置的隐式等待时间会对当前driver的整个生命周期都生效,直到调用driver.close()方法。因此,通过driver定位每一个元素都会有隐式等待的时间,这会影响测试脚本执行的效率


显示等待

针对某个元素设置等待时间,服务端(Appium)会在特定的超时时间内重试多次寻找控件

  • 在设定的时间范围内,每间隔设定的轮询时间定位指定元素,每次间隔的轮询时间内没有定位成功会忽略异常,如果超出设定时间仍未定位成功则抛出异常
  • 可以使用ExpectedConditions中的多种方法来满足不同的定位需求
     WebDriverWait wait = (WebDriverWait) new WebDriverWait(androidDriver,
                Duration.ofSeconds(10).getSeconds(),Duration.ofSeconds(1).getSeconds())
                .ignoring(NoSuchElementException.class)
                .ignoring(WebDriverException.class)
                .ignoring(UnreachableBrowserException.class)
                .ignoring(ProtocolException.class);
        WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("continueid")));
        element.click();
  • driver: appiumdriver的初始化实例
  • timeout:查询条件的最大等待时间,Duration.ofSeconds(10)代表最大的等待时间10秒
  • sleep:设置查询条件的时间频率,Duration.ofSeconds(1)代表每间隔1秒去定位元素
  • ignoring:如果每间隔1秒定位元素失败则忽略对应的异常
  • wait.until:WebDriverWait需要和until方法结合使用,通过调用ExpectedConditions里面的方法来返回你想要的值

手势操作—滑动

  • java-client 6.0版本之后的使用方式
    /**
     * @param startPointX 滑动起始坐标x
     * @param startPointY  滑动起始坐标y
     * @param endPointX    滑动结束坐标x
     * @param endPointY    滑动结束坐标y
     * @param duration      滑动耗时--默认毫秒
     */
    public void swipe(AndroidDriver<WebElement> androidDriver, int startPointX, int startPointY, int endPointX, int endPointY, int duration)
        TouchAction touchAction = new TouchAction(androidDriver);
        touchAction.press(PointOption.point(startPointX,startPointY)).waitAction(WaitOptions.waitOptions(Duration.ofMillis(duration)))
                .moveTo(PointOption.point(endPointX,endPointY)).release();
        //让滑动生效
        touchAction.perform();
    

九宫格滑动解锁


具体代码如下:

  • 首先需要定位到每个点的坐标
    public void test(AndroidDriver<WebElement> androidDriver)
        TouchAction touchAction = new TouchAction(androidDriver);
        PointOption point1 = PointOption.point(150, 427);
        PointOption point2 = PointOption.point(362, 427);
        PointOption point3 = PointOption.point(569, 427);
        PointOption point4 = PointOption.point(359, 625);
        PointOption point5 = PointOption.point(150, 850);
        PointOption point6 = PointOption.point(362, 850);
        PointOption point7 = PointOption.point(569, 850);
        touchAction.press(point1).moveTo(point2).moveTo(point3).moveTo(point4).moveTo(point5).moveTo(point6).moveTo(point7)
                .release();
        touchAction.perform();
    

多点触摸

  • 参考百度地图,双指滑动放大和缩小地图
    public void test(AndroidDriver<WebElement> androidDriver)
        MultiTouchAction multiTouchAction=new MultiTouchAction(androidDriver);
        //得到当前屏幕的高度和宽度
        int x = androidDriver.manage().window().getSize().getWidth();
        int y = androidDriver.manage().windowappium工作原理及启动方式

APP自动化测试appium环境怎么搭建?

RF+Appium框架自动化测试系列一之(Mac下Appium环境搭建)万事开头难

Appium学习笔记--安装与配置

测试Appium原理

APP自动化测试之appium连接真机启动app