uiautomator 教程

  • 简介

    UiAutomator是Google提供的用来做安卓自动化测试的一个Java库,基于Accessibility服务。功能很强,可以对第三方App进行测试,获取屏幕上任意一个APP的任意一个控件属性,并对其进行任意操作,但有两个缺点:1. 测试脚本只能使用Java语言 2. 测试脚本要打包成jar或者apk包上传到设备上才能运行。

  • 环境搭建

  1. 安装JDK,并配置好环境变量
JDK下载地址:https://pan.baidu.com/s/1Sa6Dq2a3zciuZ_9udcDwPQ    提取码:ybe7
  1. 下载SDK,解压
SDK下载地址:https://pan.baidu.com/s/1vMASKxDfsx6wo4MwhiVKnw    提取码:j525

  1. adb环境变量配置
https://blog.csdn.net/shengmer/article/details/79027828
  1. 下载eclipse,解压
eclipse下载地址:https://pan.baidu.com/s/1IXIS23S52zUG80nakaAlXQ    提取码:t1ye
  1. 下载相关jar包
jar包下载地址:https://pan.baidu.com/s/1Wv5HbN5skX4oESLDR52WHA    提取码:igge
  • 新建项目

  1. 打开eclipse,新建java 项目
点击File --> New --> Java Project --> 填写项目名 --> 点击Finish

  1. 在新建项目根目录新建libs文件夹,将开始下载的jar包,解压之后,放入libs文件夹,并引用
1:右键项目名 --> New --> Folder

2:在Folder name 栏目填写 libs --> 点击Finish

3:将开始下载的jar包,解压之后,放入libs文件夹

4:右键jar包 --> Build Path --> Add to Build Path

  1. 开始编码
1:新建类,继承 UiAutomatorTestCase
import com.android.uiautomator.testrunner.UiAutomatorTestCase;
public class xxx extends UiAutomatorTestCase {

}
2:在新建类中,写一个必须包含test字样的公开的空返回值方法
public class xxx extends UiAutomatorTestCase {
	public void testDemo() {

	}
}
3:在新建方法中,开始编写自动化代码
4:代码打包

在项目根目录新建 MyInjectEventApp.bat 文件,然后右键编辑,写入:

del classes.dex
del bin\uiTests.jar

cd bin

jar cvf  uiTests.jar *

copy uiTests.jar ..\uiTests.jar

cd ..

set PATH=%PATH%;D:\android\adt-bundle-windows-x86_64-20140702\sdk\build-tools\android-4.4W
cmd /c dx --dex --output=.\classes.dex .\uiTests.jar

aapt add test.jar classes.dex

cd bin

说明:
D:\android\adt-bundle-windows-x86_64-20140702\sdk\build-tools\android-4.4W 是上面下载的SDK文件里面android-4.4W的目录。
test.jar 是打包完成时候的jar包名字
基本写法的话, 修改这两个地方就ok。
修改之后,保存该文件,双击MyInjectEventApp.bat,等待打包完成。

5:执行打包代码
新建test.bat 文件,写入:
adb push ./test.jar /data/local/tmp/

adb shell uiautomator runtest /data/local/tmp/test.jar -c com.test.xxx -e minWait 2 -e maxWait 5 -e wordType 1

说明:
adb push:将打包完成的test.jar 脚本文件,推送到手机/data/local/tmp/ 目录下
adb shell uiautomator runtest: 执行/data/local/tmp/目录下面的test.jar脚本文件

-c 指定包名+类名 -e指定脚本接收的参数 (注意空格不能少)

脚本接收参数示例

public class xxx extends UiAutomatorTestCase {
	private int min,max;
	private String wordType;
	public void testDemo() {
		wordType = getParamsVal("wordType", "1");    
		min = Integer.parseInt(getParamsVal("minWait","2"));
		max = Integer.parseInt(getParamsVal("maxWait","8"));
	}
	
	private Bundle params = null;
	//第一个参数:-e 后面的字段 
	//第二个参数:在获取不到第一个参数的时候,设置的默认值
	public String getParamsVal(String key, String defVal) {
		String val = "";
		if (null == params)
			params = getParams();
		if (params.isEmpty()) {
			return defVal;
		}

		if (params.containsKey(key)) {
			val = params.getString(key);
			if (null == val) {
				val = defVal;
			}
		} else {
			val = defVal;
		}
		return val;
	}
}



  • uiautomatorviewer 使用方法

在手机正常连接电脑之后,找到sdk\tools\bin\uiautomatorviewer.bat 文件,双击打开。

点击这个按钮,获取手机屏幕

假如,我想要获取 “动态消息” 的信息,在uiautomatorviewer获取出来的页面中,点中 “动态消息” ,在右边可以看到。

这里可以拿到 “动态消息” 的 text, resource-id,class, content-desc 等信息。

假如,我想要获取某一位置的坐标。

这里可以拿到当前鼠标位置的坐标(309,548)
  • uiautomator API 详解

UiDevice 常用方法

在自动化测试中可以通过UiDevice对象去对设备的控制,如点亮屏幕、锁屏、旋转方向、截图等,点击home键、back键、menu键等。

pressBack() //模拟点击手机返回键

public void testDemo() {
	UiDevice uiDevice = UiDevice.getInstance();  // 获取UiDevice
	uiDevice.pressBack(); //模拟点击返回键
}

wakeUp() //唤醒屏幕

public void testDemo() {
	UiDevice uiDevice = UiDevice.getInstance();  // 获取UiDevice
	uiDevice.wakeUp(); //唤醒屏幕,如果屏幕是处于唤醒状态,则无效
}

pressHome() //点击home键

public void testDemo() {
	UiDevice uiDevice = UiDevice.getInstance();  // 获取UiDevice
	uiDevice.pressHome(); //点击home键
}

click(int x, int y) //点击界面上坐标为(x,y)的坐标点

public void testDemo() {
	UiDevice uiDevice = UiDevice.getInstance();  // 获取UiDevice
	uiDevice.click(50, 80); //点击界面上坐标为(50,80)的坐标点
}

getDisplayHeight() //获取屏幕高度

public void testDemo() {
	UiDevice uiDevice = UiDevice.getInstance();  // 获取UiDevice
	int height = uiDevice.getDisplayHeight(); //获取屏幕高度
}

getDisplayWidth() //获取屏幕宽度

public void testDemo() {
	UiDevice uiDevice = UiDevice.getInstance();  // 获取UiDevice
	int width = uiDevice.getDisplayWidth(); //获取屏幕宽度
}

pressEnter() //模拟短按回车键

public void testDemo() {
	UiDevice uiDevice = UiDevice.getInstance();  // 获取UiDevice
	uiDevice.pressEnter(); //模拟短按回车键
}

pressMenu() //模拟短按menu键

public void testDemo() {
	UiDevice uiDevice = UiDevice.getInstance();  // 获取UiDevice
	uiDevice.pressMenu(); //模拟短按menu键
}

pressKeyCode(int keyCode) //模拟短按键盘代码keycode

public void testDemo() {
	UiDevice uiDevice = UiDevice.getInstance();  // 获取UiDevice
	uiDevice.pressKeyCode(KeyEvent.KEYCODE_NUMPAD_ENTER); //模拟按回车键
}

swipe(startX, startY, endX, endY, steps) //滑动

public void testDemo() {
	UiDevice uiDevice = UiDevice.getInstance();  // 获取UiDevice
	uiDevice.swipe(10, 10, 100, 100, 50);   //从坐标点(10,10) 滑动到 坐标点(100,100) ,步长为50
}

takeScreenshot(file) //截图

public void testDemo() {
	UiDevice uiDevice = UiDevice.getInstance();  // 获取UiDevice
	String path = /data/local/tmp/" + "Tmp_" + System.currentTimeMillis() + ".png;
    File file = new File(path);   //根据文件名创建文件
	uiDevice.takeScreenshot(file);    //截图
}

registerWatcher(name, watcher) //监听器

public void testDemo() {
	UiDevice uiDevice = UiDevice.getInstance();  // 获取UiDevice
	uiDevice.registerWatcher("tips", new UiWatcher() {  
	        //tips:监听器名字
			@Override
			public boolean checkForCondition() {
				// TODO Auto-generated method stub
				
				boolean isTrue = false;
				if (isTrue) {
					System.out.println("tipUiWatcher start!!!!");
					return true;
				}
				return false;
			}
		});
	//监听器,不建议写在循环里面。
	//这段代码的意思:创建一个名为tips的监听器,在脚本执行期间,如果当isTrue = true 时,触发监听器。
}

UiDevice 暂时介绍这几个最为常用的方法


查找控件常用方法

通过resource-id查找控件,如果存在,则点击

public class xxx extends UiAutomatorTestCase {
	public void testDemo() throws UiObjectNotFoundException {
		UiObject uiObject = new UiObject(new UiSelector().resourceId("通过 uiautomatorviewer 查看到的id"));
		//设置5S ,等待控件出现,如果控件出现的时间小于5s,则正常执行
		//5s只是一个等待控件出现的最大时间,这里可以自行设置
		uiObject.waitForExists(5000);    
		if(uiObject.exists()) {   // 如果当前界面能找到这个 元素
			uiObject.click();     // 点击
		}
	}
}

通过class查找控件,如果存在,则点击

public class xxx extends UiAutomatorTestCase {
	public void testDemo() throws UiObjectNotFoundException {
		UiObject uiObject = new UiObject(new UiSelector().className("通过 uiautomatorviewer 查看到的 class"));
		//设置5S ,等待控件出现,如果控件出现的时间小于5s,则正常执行
		//5s只是一个等待控件出现的最大时间,这里可以自行设置
		uiObject.waitForExists(5000); 
		if(uiObject.exists()) {   // 如果当前界面能找到这个 元素
			uiObject.click();     // 点击
		}
	}
}

通过content-desc查找控件,如果存在,则点击

public class xxx extends UiAutomatorTestCase {
	public void testDemo() throws UiObjectNotFoundException {
		UiObject uiObject = new UiObject(
				new UiSelector().description("通过 uiautomatorviewer 查看到的 class"));
		//设置5S ,等待控件出现,如果控件出现的时间小于5s,则正常执行
		//5s只是一个等待控件出现的最大时间,这里可以自行设置
		uiObject.waitForExists(5000); 
		if(uiObject.exists()) {   // 如果当前界面能找到这个 元素
			uiObject.click();     // 点击
		}
	}
}

通过text查找控件,如果存在,则点击

public class xxx extends UiAutomatorTestCase {
	public void testDemo() throws UiObjectNotFoundException {
		UiObject uiObject = new UiObject(new UiSelector().text("通过 uiautomatorviewer 查看到的text"));
		//设置5S ,等待控件出现,如果控件出现的时间小于5s,则正常执行
		//5s只是一个等待控件出现的最大时间,这里可以自行设置
		uiObject.waitForExists(5000);
		if(uiObject.exists()) {   // 如果当前界面能找到这个 元素
			uiObject.click();     // 点击
		}
	}
}

除了通过单一属性去查找控件之外,还能通过组合的方式去查找控件,比如:

//通过id和text 组合查找控件
UiObject uiObject = new UiObject(new UiSelector().resourceId(id).text(text));

//通过id和description 组合查找控件
UiObject uiObject = new UiObject(new UiSelector().resourceId(id).description(description));

其他的,都可以自己组合。

给输入框输入内容

首先找到文本输入框
public class xxx extends UiAutomatorTestCase {
	public void testDemo() throws UiObjectNotFoundException {
		//先根据id,找到文本输入框,然后调用setMsgToEdit方法
		UiObject uiEdit = new UiObject(new UiSelector().resourceId("jp.naver.line.android:id/chathistory_message_edit"));
		if(uiEdit.exists()) {
			setMsgToEdit("你好");
		}
	}
	
	public void setMsgToEdit(String string) {
		try {
			string = URLDecoder.decode(string, "UTF-8");
		} catch (Exception e) {
		}
		try {
			Thread.sleep(500);
		} catch (Exception e) {
		}

		IClipboard iClipboard = IClipboard.Stub
				.asInterface((IBinder) ServiceManager.getService("clipboard"));
		// IInputManager.Stub.asInterface((IBinder)ServiceManager.getService("input"));
		try {
			iClipboard.setPrimaryClip(
					ClipData.newPlainText("NonASCII", string), string);
		} catch (RemoteException var1_2) {
			var1_2.printStackTrace();
		}
		paste();
		try {
			iClipboard
					.setPrimaryClip(ClipData.newPlainText("NonASCII", ""), "");
		} catch (Exception e) {
		}
	}

	private void paste() {
		UiDevice.getInstance().pressKeyCode(50, 4096);
	}
}

查找列表,循环列表,点击每一个好友,并返回:

首先找到列表,分析列表的元素,

当前界面列表元素为:class:androidx.recyclerview.widget.RecyclerView  resource-id:jp.naver.line.android:id/friend_list_recycler_view
所以:这里有两种方法去找到当前列表
第一种为通过 resource-id 查找列表
第二种为通过 class 查找列表
public class xxx extends UiAutomatorTestCase {
	public void testDemo() throws UiObjectNotFoundException {
	//注意,查找列表的时候,跟查找其他控件不一样,列表必须要使用UiScrollable
		UiScrollable uiScrollable = new UiScrollable(
				new UiSelector().resourceId("jp.naver.line.android:id/friend_list_recycler_view"));
		//设置5S ,等待控件出现,如果控件出现的时间小于5s,则正常执行
		//5s只是一个等待控件出现的最大时间,这里可以自行设置
		uiScrollable.waitForExists(5000); 
		if(uiScrollable.exists()) {   // 如果当前界面能找到这个 元素
			//其他逻辑
		}
	}
}
public class xxx extends UiAutomatorTestCase {
	public void testDemo() throws UiObjectNotFoundException {
		//注意,查找列表的时候,跟查找其他控件不一样,列表必须要使用UiScrollable
		UiScrollable uiScrollable = new UiScrollable(
				new UiSelector().className("androidx.recyclerview.widget.RecyclerView "));
		//设置5S ,等待控件出现,如果控件出现的时间小于5s,则正常执行
		//5s只是一个等待控件出现的最大时间,这里可以自行设置
		uiScrollable.waitForExists(5000); 
		if(uiScrollable.exists()) {   // 如果当前界面能找到这个 元素
			//其他逻辑
		}
	}
}
展开列表元素

通过工具可以看到,消息列表的class :android.widget.LinearLayout,resource-id:jp.naver.line.android:id/bg 所以:
public class xxx extends UiAutomatorTestCase {
	public void testDemo() throws UiObjectNotFoundException {
		//注意,查找列表的时候,跟查找其他控件不一样,列表必须要使用UiScrollable
		UiScrollable uiScrollable = new UiScrollable(
				new UiSelector().className("androidx.recyclerview.widget.RecyclerView"));
		//设置5S ,等待控件出现,如果控件出现的时间小于5s,则正常执行
		//5s只是一个等待控件出现的最大时间,这里可以自行设置
		uiScrollable.waitForExists(5000); 
		if(uiScrollable.exists()) {   // 如果当前界面能找到这个列表
			//uiScrollable.getChildCount()  当前列表,在当前界面,能看到的条数
			for (int i = 0; i < uiScrollable.getChildCount(); i++) {
				// 循环遍历当前列表,第一级元素控件
				UiObject uiItem = uiScrollable.getChild(new UiSelector().className(
						"android.widget.LinearLayout").index(i));
				if(!uiItem.exists()) continue;  // 如果控件不存在,跳过当前循环,进入下一次循环
				
			}
		}
	}
}
上面找到了第一级目录,而通过工具可以看到,需要点击好友,需要分析第一级目录下面子元素的个数
public class xxx extends UiAutomatorTestCase {
	public void testDemo() throws UiObjectNotFoundException {
		//注意,查找列表的时候,跟查找其他控件不一样,列表必须要使用UiScrollable
		UiScrollable uiScrollable = new UiScrollable(
				new UiSelector().className("androidx.recyclerview.widget.RecyclerView"));
		//设置5S ,等待控件出现,如果控件出现的时间小于5s,则正常执行
		//5s只是一个等待控件出现的最大时间,这里可以自行设置
		uiScrollable.waitForExists(5000);
		if(uiScrollable.exists()) {   // 如果当前界面能找到这个 元素
			//uiScrollable.getChildCount()  当前列表,在当前界面,能看到的条数
			for (int i = 0; i < uiScrollable.getChildCount(); i++) {
				// 循环遍历当前列表,第一级元素控件
				UiObject uiItem = uiScrollable.getChild(new UiSelector().className(
						"android.widget.LinearLayout").index(i));
				if(!uiItem.exists()) continue;  // 如果控件不存在,跳过当前循环,进入下一次循环
				
				//获取uiItem下面子元素的个数
				int size = uiItem.getChildCount();
				
				//当子元素个数大于2的时候,说明不是好友,而是其他项,所有,过滤,不点击。
				if(size > 2) continue;
				
				//点击单个好友
				uiItem.click();
				
				//让程序休息一会,等待相应
				sleep(3000);
				
				//因为点击了好友,会跳转转到另外一个界面, 所以,需要一个点击返回的操作。
				UiDevice.getInstance().pressBack();
			}
		}
	}
}
发布了1 篇原创文章 · 获赞 0 · 访问量 1525

猜你喜欢

转载自blog.csdn.net/JianXiongx/article/details/100882993