Appium常见问题处理方式—App自动化测试与框架实战(8)

发表于:2019-3-28 10:53

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:刘金起,李明黎    来源:51Testing软件测试网原创

  第11章 Appium常见问题处理方式
  本章对自动化测试中的常见问题进行总结,供平时遇到问题时进行参考。
  11.1 输入中文
  在使用Appium做手机端的自动化测试时,会遇到输入中文的问题。常见的解决方式如下。
  (1)把测试类另存为UTF-8格式。
  (2)在Desired Capabilities中增加两个属性:unicodeKeyboard和resetKeyboard。
capabilities.setCapa
bility("unicodeKeyboard", true);
capabilities.setCapability("resetKeyboard", true);
  在脚本的执行过程中可以直接输入中文,程序执行成功。
  username.sendKeys("视界");
  11.2 滑动操作
  Appium通过swipe函数处理滑动问题,如代码清单11-1所示。从代码可以看出,此方法共有5个参数,都是整型,依次是起始位置的x、y坐标和终点位置的x、y坐标,以及滑动间隔时间,单位为ms。
  代码清单11-1swipe函数
public void swipe(int startx, int starty, int endx, int endy, int duration) {
TouchAction touchAction = new TouchAction(this);
//Appium把press-wait-moveto-release转换为滑动操作
touchAction.press(startx, starty).waitAction(duration)
.moveTo(endx, endy).release();
touchAction.perform();
}
  为了让Appium更好地兼容不同分辨率的设备,需要在滑动前先获取屏幕的分辨率。
  int width = driver.manage().window().getSize().width;
  int height = driver.manage().window().getSize().height;
  然后根据屏幕的分辨率执行各种滑动操作。
//向上滑动
driver.swipe(width / 2, height * 3 / 4, width / 2, height / 4, during);
//向下滑动
driver.swipe(width / 2, height / 4, width / 2, height * 3 / 4, during);
//向左滑动
driver.swipe(width / 4, height / 2, width * 3 / 4, height / 2, during);
//向右滑动
driver.swipe(width * 3 / 4, height / 2, width / 4, height / 2, during);
  以大众点评网的App为例,在大众点评网首页中,单击"美食"图标(如图11-1所示),弹出图11-2所示界面。
  
  "美食"界面罗列了很多美食的信息。"深×××"不在"美食"界面中,需要向上滑动页面,让"深×××"显示出来并单击进入"深×××"对应的列表项。
  实现的代码如代码清单11-2所示。
  代码清单11-2大众点评网示例
public  void testSwip() throws InterruptedException{
boolean up;
//美食图标
MobileElement meishiElement = (MobileElement) driver.findElement(By.xpath
("// android.support.v7.widget.RecyclerView/android.widget.RelativeLayout[1]
/android.widget.ImageView"));
//单击美食图标,跳转到美食界面
meishiElement.click();
//获取当前页面的屏幕尺寸
int width = driver.manage().window().getSize().width;
int height = driver.manage().window().getSize().height;
while(true){
try{
MobileElement endElement = (MobileElement) driver.findElement(By.xpath
("//android.widget.TextView[@text='深×××']"));
endElement.click();
break;
}catch(Exception e){
driver.swipe(width / 2, height * 3 / 4, width / 2, height / 4, 1000);
Thread.sleep(2000);
}
}
}
  11.3 滚动操作
  Appium早期版本提供了Scroll方法来实现滚动,最新的版本已经取消了这个方法。笔者使用findElementByAndroidUIAutomator()方法来实现同样的功能,如代码清单11-3所示。
  代码清单11-3滚动操作的实现
public void scrollToElement(String str) {
((AndroidDriver<MobileElement>) driver).findElementByAndroidUIAutomator(
"new UiScrollable(new UiSelector().scrollable(true).instance(0)).ScrollIntoView
(new UiSelector().textContains(\""+ str + "\").instance(0))");
}
public void scrollToExactElement(String str) {
((AndroidDriver<MobileElement>) driver).findElementByAndroidUIAutomator(
"new UiScrollable(new UiSelector().scrollable(true).instance(0)).scrollIntoView
(new UiSelector().textContains(\""+ str + "\").instance(0))");
}
  findElementByAndroidUIAutomator()要求传入的参数为字符串。
  UiSelector().scrollable(true) .instance(0)表示找到一个可以滑动的对象,通过判断scrollable属性是否为true进行查找。
  scrollIntoView滑动到匹配的selector控件,如果没有匹配到,则停留在滑动列表的最下方。
  在new UiSelector().text(string).instance(0)待匹配的selector控件中,设置text属性值为指定的string。
  UiSelector().textContains(string).instance(0))待匹配的selector控件,指定text属性值包含指定的string。
  11.4 输入Android按键
  在清除编辑框的内容时,采用以下步骤。
  (1)获取编辑框中文本的长度。
  (2)将光标移动到文本的尾部。
  (3)按退格直到所有文本被删除。
  如代码清单11-4所示,参考6.2.2节,按键123表示光标移动到末尾,按键67表示退格键。
  代码清单11-4输入Android按键
/**
* 描述:清理文本框
* 参数:文本框的内容
*/
public void clearText(String text) {
for (int i = 0; i < text.length(); i++) {
//123:KEYCODE_MOVE_END 光标移动到末尾
driver.pressKeyCode(123);
//KEYCODE_DEL 退格键 67
driver.pressKeyCode(67);
}
}
}
  11.5 处理Popup Window
  Popup Window是一个弹出窗口控件,可以用来显示任意视图(View),而且会浮动在当前活动(Activity)的顶部。通过UI Automator Viewer无法识别,通过Hierarchy Viewer才可以识别到Popup Window。这属于系统逻辑,Appium暂时没有处理机制,可以采用下面的方法进行解决。
  " 通过Tap方法,代码如下。
WebElement imagebtn = driver.findElementById("showPopupWindowButton");
magebtn.click();
driver.tap(1, 214, 475, 10);
  " 通过TouchAction,代码如下。
WebElement imagebtn2 = driver.findElementById("showPopupWindowButton");
imagebtn2.click();
TouchAction action = new TouchAction(driver);
action.press(214, 475).release().perform();
  对于需要操作的Popup Window,用户可以首先获得坐标点,然后以封装为Hash函数的方式进行操作。例如弹出框上有4个蓝色的球,要获取每个球的坐标点,可以封装这4个坐标点到一个Hash函数中,如代码清单11-5所示,在其他方法中通过调用Hash函数实现对任意蓝色的球进行操作,如代码清单11-6所示。这里采用的是绝对坐标,考虑到分辨率的问题,建议对相对坐标进行封装。
  代码清单11-5获取坐标点并封装
package appiumsample;
import java.util.*;
import org.openqa.selenium.Point;
public class Popuppointer {
//获得蓝球的坐标
public void blueball(){
Point x1 = new Point(1013, 534);
Point x2 = new Point(1114,534);
Point x3 = new Point(1210,534);
Point x4 = new Point(1294,534);
HashMap<Integer, Point> blueball= new HashMap<Integer, Point>();
blueball.put(1,x1);
blueball.put(2,x2);
blueball.put(3,x3);
blueball.put(4,x4);
}
}
  调用方法如代码清单11-6所示。
  代码清单11-6调用Hash函数
driver.tap(1,Popuppointer.blueball().get(1).x,Popuppointer.blueball().get(1).y,30);
driver.tap(1,Popuppointer.blueball().get(2).x,Popuppointer.blueball().get(2).y,30);
driver.tap(1,Popuppointer.blueball().get(3).x,Popuppointer.blueball().get(3).y,30);
driver.tap(1,Popuppointer.blueball().get(4).x,Popuppointer.blueball().get(4).y,30);
  Popup Window无法识别,很大程度上是因为焦点无法找到,以上方法仅适用于无源码的情况。
  11.6 处理Toast
  Toast是Android中用来显示信息的一种机制,和Dialog不一样的是,Toast是没有焦点的,而且Toast显示的时间有限,过一定的时间就会自动消失。此外,它主要用于向用户显示提示消息。Toast属于Android系统逻辑,不属于应用逻辑,所以通过UI Automator Viewer无法获取控件。可以采用下面的方法进行解决。
  1.图片比对方法
  在Toast被触发后,截取界面的图片,然后进行比对,如代码清单11-7所示。
  代码清单11-7对比图片
WebElement imagebtn = driver.findElementById("showToastButton");
imagebtn.click();
try{
File scrFile =driver.getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(scrFile, new File("D:\\scrshot.png"));
}
catch(Exception e){
e.printStackTrace();
}
  通过getScreenshotAs方法来捕捉屏幕,如代码清单11-7所示,使用OutputType.FILE作为参数传递给getScreenshotAs,告诉它将截取的屏幕以文件的形式返回。使用copyFile保存getScreenshotAs截取的屏幕文件到D盘中并命名为scrshot.png。
  因为Toast一般显示有限的时间就会自动消失,所以在截取图片的时候,建议多截取几张,以保证截取成功。
  2.Seledroid方法
  Seledroid方法(自动化测试引擎)可以识别Toast控件,采用WaitForElement方法获得Toast上的文本。
  waitForElement(By.partialLinkText("Hello seledroid toast"), 4, driver);
  3.使用Automator2
  在最新版本的Appium中,使用Automator2自动化测试引擎,可以获取Toast。升级Appium为GUI 1.2.3版本,如代码清单11-8所示。
  代码清单11-8在Appium中处理Toast
package com.shijie.testScripts;
import static org.testng.Assert.assertNotNull;
import io.appium.java_client.android.Activity;
import io.appium.java_client.android.AndroidDriver;
import java.io.File;
import java.net.URL;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import io.appium.java_client.remote.AutomationName;
import io.appium.java_client.remote.MobileCapabilityType;
public class testkongjian {
AndroidDriver<WebElement> driver;
@BeforeMethod
public void SetUp() throws Exception  {
File appDir = new File("F:\\");
File app = new File(appDir, "selendroid-test-app-0.17.0.apk");
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Android Emulator");
capabilities.setCapability(MobileCapabilityType.APP, app.getAbsolutePath());
capabilities.setCapability(MobileCapabilityType.AUTOMATION_NAME,
AutomationName.ANDROID_UIAUTOMATOR2);
driver = new AndroidDriver<>(new URL("http://127.0.0.1:4723/wd/hub"), capabilities);
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
}
@Test
public void test_toast(){
Activity activity = new Activity("io.selendroid.testapp", ".HomeScreenActivity");
driver.startActivity(activity);
WebElement toastButton = null;
toastButton = driver.findElement(By.id("io.selendroid.testapp:id/showToastButton"));
toastButton.click();
final WebDriverWait wait = new WebDriverWait(driver, 10);
assertNotNull(wait.until(ExpectedConditions.presenceOfElementLocated(
By.xpath("//*[@text='Hello selendroid toast!']"))));
}
@AfterMethod
public void TearDown()
{
driver.quit();
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
}
}

版权声明:51Testing软件测试网获人民邮电出版社和作者授权连载本书部分章节。
任何个人或单位未获得明确的书面许可,不得对本文内容复制、转载或进行镜像,否则将追究法律责任。
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号