UiAutomator是Google提供的用来做安卓自动化测试的一个Java库,基于Accessibility服务。功能很强,可以对第三方App进行测试,获取屏幕上任意一个APP的任意一个控件属性,并对其进行任意操作,但有两个缺点:1. 测试脚本只能使用Java语言 2. 测试脚本要打包成jar或者apk包上传到设备上才能运行。
JDK下载地址:https://pan.baidu.com/s/1Sa6Dq2a3zciuZ_9udcDwPQ 提取码:ybe7
SDK下载地址:https://pan.baidu.com/s/1vMASKxDfsx6wo4MwhiVKnw 提取码:j525
https://blog.csdn.net/shengmer/article/details/79027828
eclipse下载地址:https://pan.baidu.com/s/1IXIS23S52zUG80nakaAlXQ 提取码:t1ye
jar包下载地址:https://pan.baidu.com/s/1Wv5HbN5skX4oESLDR52WHA 提取码:igge
点击File --> New --> Java Project --> 填写项目名 --> 点击Finish
1:右键项目名 --> New --> Folder
2:在Folder name 栏目填写 libs --> 点击Finish
3:将开始下载的jar包,解压之后,放入libs文件夹
4:右键jar包 --> Build Path --> Add to Build Path
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;
}
}
在手机正常连接电脑之后,找到sdk\tools\bin\uiautomatorviewer.bat 文件,双击打开。
点击这个按钮,获取手机屏幕
假如,我想要获取 “动态消息” 的信息,在uiautomatorviewer获取出来的页面中,点中 “动态消息” ,在右边可以看到。
这里可以拿到 “动态消息” 的 text, resource-id,class, content-desc 等信息。
假如,我想要获取某一位置的坐标。
这里可以拿到当前鼠标位置的坐标(309,548)
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();
}
}
}
}