【测试】安卓自动化测试代码片段Java

【前言】

编写安卓自动化测试代码,本文选择的是夜神模拟器+Appium

【语言选择】

Appium使用的是C/S架构方式,Client端可以支持的编程语言挺多的,本文选择的是Java

【IDE选择】

编写Java代码,本文选择的IDE是eclipse

【eclipse基础配置】

使用Maven管理项目的依赖包

【依赖包】

在网站(https://mvnrepository.com/)中搜索需要安装的依赖包的Maven代码放入pom.xml文件中

【需要的依赖包】

1 java-client

2 testNG

启动夜神模拟器中的驾考宝典app的配置:

// 1 创建配置对象
DesiredCapabilities desiredCapabilities = new DesiredCapabilities();

// 2 添加配置-测试的设备
desiredCapabilities.setCapability("deviceName", "127.0.0.1:62001");
// 2 添加配置-测试的平台
desiredCapabilities.setCapability("platformName", "Android");
// 2 添加配置-测试的App
desiredCapabilities.setCapability("appPackage", "com.handsgo.jiakao.android");
// 2 添加配置-测试App的启动入口
desiredCapabilities.setCapability("appActivity", "com.handsgo.jiakao.android.splash.Login");

// 3 创建驱动(参数:Appium通讯地址 配置参数)
androidDriver = new AndroidDriver<WebElement>(new URL("http://127.0.0.1:4723/wd/hub"), desiredCapabilities);

更改配置,解决输入框不能输入数据的问题

// 2 添加配置-更改自动化引擎来解决输入框输入不了数据的问题
desiredCapabilities.setCapability("automationName", "uiautomator2");

更改配置,不清除应用的数据启动测试(默认和设置为true时为不清除)

desiredCapbilities.setCapability("noReset", "true");

元素等待

在自动化过程中,元素的出现受到网络环境,设备性能等多种因素影响。因此元素加载的时间可能不一致,从而会导致元素无法定位超时报错。

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

元素等待方式1:强制等待

固定的等待时间

Thread.sleep(8000);//等待8秒

元素等待方式2:隐式等待

针对全局元素设置等待时间,如果没有定位到UI元素,脚本可以在全局等待时间长度内进行反复查询定位,定位成功后会提前结束等待,继续接下来的执行任务

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

元素等待方式3:显示等待

针对某个元素设置等待时间

WebDriverWait webDriverWait = new WebDriverWait(androidDriver, 10);
WebElement webElement = webDriverWait.until(new ExpectedCondition<WebElement>() {
    @Override
    public WebElement apply(WebDriver arg0) {
        return  androidDriver.findElementById("com.handsgo.jiakao.android:id/btn_agree");
    }
});
webElement.click();    

定位UI元素的方式

定位方式1:ID定位

ID就是一个控件的唯一身份标识,由开发人员在项目中指定,如果有对应的resource-id,可以采取这种方式来实现定位操作。

注意:有可能app开发人员并不是很严谨,一个界面会出现多个相同的id,这种情况下默认定位到第一个有此id的元素。

测试用例代码示例:

androidDriver.findElementById("com.handsgo.jiakao.android:id/btn_agree").click();

如果有多个相同id的情况:

List<WebElement> listElements = androidDriver.findElementById("com.handsgo.jiakao.android:id/btn_agree");

listElements.get(2).click();

定位方式2:text定位

Appium 1.5之前的版本支持By.name方式,比如:

// 根据text属性进行定位
androidDriver.findElementByname("上海");

Appium 1.5之后的版本不再支持By.name方式,需要使用UIAutonator原生自动化引擎,比如:

// 使用UIAutomator定位text属性元素
androidDriver.findElementByAndroidUIAutomator("new UiSelector().text("上海")");

【注意】如果该方式调用不出,检查一下jre的版本是否在1.5以上,更改方式如下:

第一步:

 第二步:

 第三步:

定位方式3:className定位(弃用)

根据class属性定位元素,一般在页面中很多元素的class属性一致,所以这种方式基本上不使用

定位方式4:xpath定位

Appium也可以支持xpath定位,在项目中此种方式能够使用多场景,xpath定位在web自动化测试中可以使用在app自动化测试中也可以使用,xpath定位有两种定位方式,一种是绝对位置定位另一种是相对位置定位,相对位置定位使用更加普遍,因为如果使用绝对位置定位UI元素有所改变的情况下,相关UI元素的xpath都需要相应进行改变。xpath相对路径需要使用到class属性和text属性内容进行拼接:

androidDriver.findElementByXPath("//android.widget.TextView[@text='上海']").click();

定位方式5:accessibility id定位

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

注意:很多UI元素没有这个属性

androidDriver.findElementByAccessibilityId("上海").click();

定位方式6:坐标定位

选择设置中关于手机-连续点击五次版本号-进入开发者选项-勾选指针位置

注意:坐标定位受设备屏幕尺寸/分辨率/DPI影响,万不得已不要使用此种方式定位元素

定位方式7:Toast元素的获取

获取要求:Java-client 5.0+、使用UIAutomator2自动化引擎、Android系统版本5.0+

获取方法:

WebElement toastElement = androidDriver.findElementByXPath("//*[contains(@text, '用户名与密码')]");
System.out.print(toastElement.getText());

对UI元素的操作

UI元素操作1:点击操作

.click();//点击

UI元素操作2:输入操作

.sendKeys("深圳");//输入

UI元素操作3:滑动手势

Java-clilent 5.0之前版本提供的滑动API

// Java-client 4.1.2
androidDriver.swipe(356, 594, 356, 794, 800);
// (起始点坐标x, 起始点坐标y, 终止点坐标x, 终止点坐标y, 滑动时间)

Java-client 5.0之后需要自定义实现(可采用之前版本的实现思路)

// Java-client 6.1.0
TouchAction touchAction = new TouchAction(androidDriver);

PointOption startPointOption = PointOption.point(356, 594);
PointOption endPointOption = PointOption.point(356, 794);
Duration duration = Duration.ofMillis(800);
WaitOptions waitOptions = WaitOptions.waitOptions(duration);

touchAction.press(startPointOption).waitAction(waitOptions).moveTo(endPointOption).release();
touchAction.perform();// 让滑动生效

滑动的使用场景:下拉刷新、手势解锁等

手势解锁需要滑动到多个点,代码上使用多个.moveTo()方法就行了:

touchAction.press(pointOption1).waitAction(waitOptions).moveTo(pointOption2).moveTo(pointOption3).moveTo(pointOption4).release();

UI元素操作4:多点触摸手势

使用场景:地图缩放

MultiTouchAction类可以模拟用户多点触摸操作

主要包含有add()和perform()两个方法

可以结合TouchAction模拟多根手指滑动效果

// 1 实例化MultiTouchAction对象
MultiTouchAction multiTouchAction = new MultiTouchAction(androidDriver);
// 2 实例化两个TouchAction(因为需要两根手指进行放大操作)
TouchAction touchAction1 = new TouchAction<>(androidDriver);
TouchAction touchAction2 = new TouchAction<>(androidDriver);
// 3 得到当前屏幕的高度和宽度
int x = androidDriver.manage().window().getSize().getWidth();
int y = androidDriver.manage().window().getSize().getHeight();
// 第一根手指的滑动
touchAction1.press(PointOption.point(x * 4 / 10, y * 4 / 10))
.waitAction(WaitOptions.waitOptions(Duration.ofMillis(1000)))
.moveTo(PointOption.point(x * 2 / 10, y * 2 / 10)).release(); // 第二根手指的滑动 touchAction2.press(PointOption.point(x * 6 / 10, y * 6 / 10))
.waitAction(WaitOptions.waitOptions(Duration.ofMillis(1000)))
.moveTo(PointOption.point(x * 8 / 10, y * 8 / 10)).release(); // 把两根手指的动作添加到MultiTouchAction里面 multiTouchAction.add(touchAction1).add(touchAction2); multiTouchAction.perform();

断言

使用testNG集成断言框架 ,选择src/test/java中的.java文件,右击选择“testNG”-->“Convert to TestNG”,如下图所示

 (如果右击没有TestNG选项,可以在eclipse中的MarketPlace中搜索TestNG在线安装)

之后在项目中会自动生成一个testng.xml文件,在刚刚选中的java文件中会在一些方法前面有@Test标识,测试开始之前的初始化@BeforeTest标识,刻可以将之前放在main函数中的执行代码放置到beforeTest标识下的自定义setup方法中,然后把main函数去掉。使用@AfterTest标识的函数用来当测试用例运行完毕后销毁测试驱动(调用测试驱动对象的quit方法)。此后运行方式使用"Run As"--"TestNG Test"。

断言1:检查当前展示的界面是否是测试用例预期的结果

先确定预期界面类的名字,终端执行

adb shell dumpsys activity | find "mFocusedActivity"

输出的结果中,斜杠后面的一长串就是类名,例如下图所示

在测试用例中:

String expected = "cn.mucang.android.mars.student.refactor.business.inquiry.activity.InquiryActivuty";
String actual = androidDriver.currentActivity();
Assert.assertEquals(actual, expected);

运行完之后会有一个测试报告自动生成。

Appium常用API

Appium常用API1:实现页面跳转(startActivity)

页面跳转,包括App内部页面及App相互跳转

// 开启某一个activity,实现跳转
// 首先我们需要创建activity对象,用activity构建方法初始化,参数为对应的包名和类名
Activity activity = new Activity("com.lemon.lemonban", "com.lemon.lemonban.LoginActivity");
androidDriver.startActivity(activity);

注意:如找不到startActivity方法,请确认你的eclipse java compiler是否设置的是JDK1.8

Appium常用API2:得到当前页面的dom结构(getPageSource)

可以用于断言当前页面是否有某个元素,或者判断当前页面有没有产生变化,比如上下滚动判断是否已经到了底端或者顶端。

String pageSource = androidDrivr.getPageSource();
System.out.println(pageSource);

Appium常用API3:得到当前页面的类名(currentActivity)

String currentActivityName = androidDrivr.currentActivity();
System.out.println(currentActivityName);

Appium常用API4:重置应用的数据(resetApp)

有些场景我们需要清除应用的数据,相当于第一次安装时候的状态,比如:第一次启动app的引导页,登录等

androidDriver.resetApp();

Appium常用API5:判断App是否安装(isAppInstalled)

androidDriver.isAppInstalled("应用程序的包名");

Appium常用API6:向系统发送键值事件(pressKey)

Android平台独有,向系统发送键值事件,不同的键值对应不同的功能,如keyevent(4)表示手机的HOME按键

// 1 创建keyEvent对象
KeyEvent keyEvent = new keyEvent();
// 2 使用withKey传入键值
keyEvent.withKey(AndroidKey.VOLUME_UP);
// 3 使用pressKey发送键值
androidDriver.pressKey(keyEvent);

Appium常用API7:截图功能

使用场景:当测试用例执行失败之后屏幕截图,保存到本地为了更好的查找问题

File file = androidDriver.getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(file, new File("D:\AppAuto\test.png"));

Appium常用API8:获取设备时间信息(getDeviceTime)

返回String类型

Appium常用API9:获取设备DPI(getDisplayDensity)

返回String类型,注意不是分辨率

Appium常用API10:获取automation name(getAutomationName)

默认为null,如果有指定automation name为uiautomator2就为对应的值

Appium常用API11:获取设备横竖屏状态(getOrientation)

有竖屏(PORTRAIT)和横屏(LANDSCAPE)

【root状态的Hybrid应用自动化测试介绍】

Appium提供的解决方案:基于UIAutomator+ChromeDriver

准备工作:

1 准备Android 4.4+的手机或者模拟器

2 在app源码中将webview调试模式打开webview.setWebContentsDebuggingEnabled(true)

如果是第三方线上app,一般webview debug开关都是关闭的,这就需要借助第三方工具,才能将debug开关打开

解决方案:(Root状态 )

Xposed.apk+WebviewDebugHook.apk装入模拟器或者是手机上

Xposed是一个框架,能够集成很多功能模块,这些模块能够在不修改APK的情况下,修改APP的运行方式。

安装好Xposed打开显示没有激活,需要在official菜单中选择安装,安装前需要选择适应的框架,如果是模拟器一般是x86框架,如果是真机需要选择arm框架。

需要WebviewDebugHook模块来开启APP的WebView debug模式 。

安装并激活好Xposed之后将WebviewDebugHook.apk放入模拟器或者手机,注意此时不会提示安装成功,需要在Xposed中找到“模块”菜单,找到WebviewDebugHook并勾选上,然后重启设备就会生效。

3 在电脑上安装UC开发者工具(uc-devtools.msi,设置成“本地Devtools Inspector UI资源”)

UC-Dectools工具的使用需要上面两步配置的支持才能使用,当模拟器或者手机上的当前界面是webView时UC-Dectools工具会检测到,点击UC-Dectools工具上面的“inspect”按钮进入到UI定位界面。

【Hybrid应用自动化脚本编写】

# 获取所有的上下文contexts

driver.getContextHandles();

# 切换到对应的上下文context

driver.context(webview视图对应的上下文);

# 定位webview中的元素,并执行操作

web网页元素定位和操作,利用Appium提供的解决方案:基于UIAutomator+ChromeDriver,进行webview中元素的定位

# 切换回默认的视图

driver.context(native视图);

示例:

// 1 进入到web页面中
androidDriver.findElementByAndroidUIAutomator("new UiSelector().text("网页版")").click();
// 2 获取所有的contexts
Set<String> contexts = androidDriver.getContextHandles();
System.out.printIn(contexts);
// 3 切换到webview所对应的上下文
androidDriver.context("WEBVIEW_COM.wuba"); 
// 4 找到网页中的“价格区间”按钮
androidDriver.findElementByXPath("//li[@data-id='p25-30']").click();
// 5 点击网页中的“确认”按钮
androidDriver.findElementByXPath("//a[text()='确认']").click();

 【注意】在上面的切换到webview所对应的上下文操作中可能会遇上因为ChromeDriver和webView的版本不匹配所导致的错误。简单来说就是,ChromeDriver是appium中的一个工具,app中使用的webview有自己的版本号,ChromeDriver每个版本对webview的可支持版本都不一样,所以需要保证版本的可支持性。

1 查看ChromeDriver版本号,mac电脑的appium中ChromeDriver所在路径为:

/Applications/Appium.app/Contents/Resources/app/node_modules/appium/node_modules/appium-chromedriver/chromedriver

双击会终端运行ChromeDriver会显示出版本号,如下图所示

2 查看模拟器或者手机的webview版本号,有三种方式:

1)在模拟器或者真机上打开一款需要webview的app,然后进入到设置-应用程序中打开“显示系统进程”,找到类似下图所示的进程:

然后点击进去便可查看到版本号:

2)通过UC-Dectools工具中检测到的webview时,信息上会附带有版本信息。

3)使用adb工具,首先确保连接上夜神模拟器

$adb connect 127.0.0.1:62001

可以通过下面的命令确保是否连接成功:

$adb devices

然后查看系统的所有程序:

$adb shell pm list package -s

找到webview:

 复制好此包名,然后查看该应用包的信息:

adb shell dumpsys package com.google.android.webview

最后找到关于version的相关信息:

3 第三步对照版本匹配表,在github可以查询到淘宝的镜像网站:

github上appium【https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/web/chromedriver.md 

淘宝的镜像网站【http://npm.taobao.org/mirrors/chromedriver

我电脑上的appium中的ChromeDriver版本号通过上面方式的查询是2.38版本,在镜像网站上找到对应的2.38目录,点击进去长相如下:

 前面三个是安装包,点击最后一个文件“notes.txt”查看该ChromeDriver版本支持哪些webview版本:

4 如果版本不匹配,替换掉appium中的ChromeDriver应用程序。

比如本文所示,通过查看ChromeDriver的版本是2.38版本,支持的webview是65-67版本;通过查看webview的版本是75,存在不匹配的情况,因为webview的版本不能更改,因此只能替换掉appium中的ChromeDriver应用程序。

【非root状态的Hybrid应用自动化测试解决方案】

解决方案:通过VirtualXposed完成线上App开启webview调试,VirtualXposed相当于一个“应用分身”提供一个虚拟环境,这个虚拟环境中默认装了一个Xposed,

1 将VirtualXpose.apk安装到真机中,在VirtualXposed中安装WebviewDebugHook.apk和需要测试的app安装包

2 在VirtualXposed中打开测试的目标app,就相当于在root状态下测试app

原文地址:https://www.cnblogs.com/cchHers/p/14167636.html