uiautomation使用详解(如何注入click事件与Android UiAutomation.injectInputEvent)

本文目录
如何注入click事件与Android UiAutomation.injectInputEvent
方法1:使用内部APIs该方法和其他所有内部没有向外正式公布的APIs一样存在它自己的风险。原理是通过获得WindowManager的一个实例来访问injectKeyEvent/injectPointerEvent这两个事件注入方法。复制代码代码如下:IBinderwmbinder=ServiceManager.getService("window");IWindowManagerm_WndManager=IWindowManager.Stub.asInterface(wmbinder);ServiceManager和Windowsmanager被定义为存根Stubs类。我们根据我们的需要绑定上这些服务并访问里面的方法。Tosendakeydothefollowing:通过以下方式发送一个事件:复制代码代码如下://keydownm_WndManager.injectKeyEvent(newKeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_A),true);
如何使用UIAutomation进行iOS自动化测试
1. 你的第一个UIAutomation测试脚本
UIAutomation的功能测试代码是用Javascript编写的。UIAutomation和Accessibility有着直接的关系,你将用到通过标签和值的访问性来获得UI元素,同时完成相应的交互操作。
下面让我们来编写我们的第一段测试代码。
使用iOS模拟器
1. 下载示例应用程序TestAutomation.xcodeproj,并打开它。这个项目是一个很简单的包含2个tab的tabbar应用程序。
2. 确保选中如下图所示的“TestAutomation 》 iPhone 5.0 Simulator”模式(或许你已经切换成5.1了,因此它可能是iPhone5.1模拟器)。
3. 启动Instruments(Product 》 Profile),或者通过⌘I。
4. 选择左边的iOS Simulator,然后再选择Automation模板,然后点击“Profile”。
5. Instruments就已经启动好后,然后直接开始录制了。这里先停止录制,(红包按钮或者⌘R)。
6. 在左边的Scripts窗口,点击“Add 》 Create”创建新的脚本。
7. 在脚本器里,输入下面的代码
var target = UIATarget.localTarget();
var app = target.frontMostApp();
var window = app.mainWindow();
target.logElementTree();
clip_image007
8. 重新运行这段脚本⌘R(不需要保存)。脚本跑起来后,你可以在日志打完后停止它。
clip_image009
赞一个!我们就这样完成了我们的第一个UIAutomation测试用例。
使用iOS设备
你除了将你的测试用例运行模拟器上,也可以将它运行在一个真实的设备上。不过,自动化测试用例只能运行在支持多任务的:iPhone 3GS,iPad,iOS 》 4.0等设备上。遗憾的是不管iPhone 3G的系统版本是什么,都不支持。
下面是如何操作:
1. 通过USB接口连接上你的iPhone。
2. 选择 “TestAutomation 》 iOS Device”模式。
3. 确保Developper profile设置成Release模式(而不是Ad-Hoc Distribution profile)。默认情况下,profiling是设置成Release模式的(因为没有必要将profile设置成Debug模式)。
4. 启动测试
5. 后面的步骤请参考前面模拟器部分。
2. 处理UIAElement和元素可访问性(Accessibility)
UIAElement层次结构
Accessibility和UIAutomation有密切的联系:如果一个控件的Accessibility是可以被访问的,你就可以设置和读取它的值,作相关的操作,而当一个控件的Accessibility不可见时,你就没有办法通过automation访问它。
你可以通过Interface Builder,或者通过在程序里设置isAccessibilityElement属性的方式来设置一个控件的Accessibility或者可被自动化。当你设置container view(即:一个视图包含其它的UIKit元素)的accessibility时,你必须注意。你设置了整个View的accessibility将会“隐藏”它的子视图的accessibility,例如:在示例项目中,你不能将outlet视图设置成可访问的,否则它所有的子控件将都不可以访问了。在任何时候,logElementTree都是你忠实的朋友:它将当前界面的所有可被访问的元素都打印在日志里。
每一个可以被访问的UIKit控件都可以用一个Javascript对象来描述,它就是一个UIAElement。UIAElement有几个属性:name, value, elements, parent。你的主窗口包含很多的控件,它们是以UIKit层次的方式定义的,这些UIKit层次结构对应的是UIAElement的层次树。例如:前面的测试代码中,通过调用logElementTree,我们可以得到如下面所示的树结构:
+- UIATarget: name:iPhone Simulator rect:{{0,0},{320,480}}
| +- UIAApplication: name:TestAutomation rect:{{0,20},{320,460}}
| | +- UIAWindow: rect:{{0,0},{320,480}}
| | | +- UIAStaticText: name:First View value:First View rect:{{54,52},{212,43}}
| | | +- UIATextField: name:User Text value:Tap Some Text Here ! rect:{{20,179},{280,31}}
| | | +- UIAStaticText: name:The text is: value:The text is: rect:{{20,231},{112,21}}
| | | +- UIAStaticText: value: rect:{{145,231},{155,21}}
| | | +- UIATabBar: rect:{{0,431},{320,49}}
| | | | +- UIAImage: rect:{{0,431},{320,49}}
| | | | +- UIAButton: name:First value:1 rect:{{2,432},{156,48}}
| | | | +- UIAButton: name:Second rect:{{162,432},{156,48}}
clip_image001
你可以通过下面的代码来访问文本框:
var textField =
UIATarget.localTarget().frontMostApp().mainWindow().textFields();
你可以选择通过从0开始的索引或者这个元素的名称来访问这个元素,例如:你也可以通过下面的代码来访问文本控件。
var textField =
UIATarget.localTarget().frontMostApp().mainWindow().textFields();
后一种方式更加清晰明了,应该多使用。你可以通过Interface Builder设置UIAElement的name属性,
clip_image002
或者通过编写代码的方式:
myTextField.accessibilityEnabled = YES;
myTextField.accessibilityLabel = @"User Text";
你现在可以看到,通过accessibility属性可以被UIAutomation用来找到不同的控件。这非常的清晰,因为,第一,你只要学习一个测试框架;第二,通过编写自动化测试代码,你同时还可以保证你的程序是可以被访问的。因此,每一个UIAElement对象的子控件可以通过下面的方法进行访问:
buttons(), images(), scrollViews(),textFields(), webViews(), segmentedControls(), sliders(), staticTexts(), switches(), tabBar(),tableViews(), textViews(), toolbar(), toolbars() 等等……
你可以通过如下代码在tabbar上访问第一个tab:
var tabBar = UIATarget.localTarget().frontMostApp().tabBar();
var tabButton = tabBar.buttons();
UIAElement结构层次非常的重要,你以后会常常用到它。而且你还要记住,你可以在随时通过调用UIAAplication的logElementTree来获得它的结构。
UIATarget.localTarget().frontMostApp().logElementTree();
在模拟器上,你还可以激活Accessibility 的检测器。启动模拟器,找到“Settings 》 General 》 Accessibility 》 Accessibility Inspector”,然后将它设为“打开”状态。
这个彩色的小框框就是Accessibility 检测器了。当它收起来的时候,Accessibility就被关闭了,当它展开的时候,Accessibility就是打开的。你只要点击上面的箭头按钮就可以激活或者屏蔽Accessibility。现在,打开我们的示例程序,激活检测器。
然后,点击文本框,检查UIAElement的name和value属性(其实就是accessibilityLabel和accessibilityValue对应的NSObject类型的值)。这个检测器可以帮助你调试和编写你的测试代码。
模拟用户操作
让我们更进一步,模拟一些用户的交互操作。你可以简单地调用按钮的tap()来作一个点击操作:
var tabBar = UIATarget.localTarget().frontMostApp().tabBar();
var tabButton = tabBar.buttons();
// Tap the tab bar !
tabButton.tap();
你还可以调用UIAButtons的doubleTap(), twoFingerTap()。如果你不想操作具体的某个元素,你也可以直接根据屏幕上指定的坐标点进行操作,你可以这么用:
UIATarget.localTarget().tap({x:100, y:200});
UIATarget.localTarget().doubleTap({x:100, y:200});
UIATarget.localTarget().twoFingerTap({x:100, y:200});
UIATarget.localTarget().pinchOpenFromToForDuration({x:20, y:200},{x:300, y:200},2);
UIATarget.localTarget().pinchCloseFromToForDuration({x:20, y:200}, {x:300, y:200},2);
拖拽与划动:
UIATarget.localTarget().dragFromToForDuration({x:160, y:200},{x:160,y:400},1);
UIATarget.localTarget().flickFromTo({x:160, y:200},{x:160, y:400});
注意,当你指定操作的时间间隔的时候,它是有特定的范围的,即:拖拽操作的时间间隔必须大于或者等于0.5秒,小于60秒。
现在,让我们来练习一下:
停止Instruments (⌘R)
在Scripts窗口里, 移除当前的脚本
点击“Add 》 Import”然后选择TestAutomation/TestUI/Test-1.js(将下面的代码保存到这个路径)
点击录制按钮 (⌘R) 然后看看将会发生什么…
下面是Test-1.js代码:
var testName = "Test 1";
var target = UIATarget.localTarget();
var app = target.frontMostApp();
var window = app.mainWindow();
UIALogger.logStart( testName );
app.logElementTree();
//-- select the elements
UIALogger.logMessage( "Select the first tab" );
var tabBar = app.tabBar();
var selectedTabName = tabBar.selectedButton().name();
if (selectedTabName != "First") {
tabBar.buttons().tap();
}
//-- tap on the text fiels
UIALogger.logMessage( "Tap on the text field now" );
var recipeName = "Unusually Long Name for a Recipe";
window.textFields().setValue(recipeName);
target.delay( 2 );
//-- tap on the text fiels
UIALogger.logMessage( "Dismiss the keyboard" );
app.logElementTree();
app.keyboard().buttons().tap();
var textValue = window.staticTexts().value();
if (textValue === recipeName){
UIALogger.logPass( testName );
}
else{
UIALogger.logFail( testName );
}
这段脚本先启动待测程序,然后,如果第一个tab没有被选的话就切换到第一个tab,并将上面的文本框的值设成“Unusually Long Name for a Recipe”,接着收起虚拟键盘。这里有一些新的方法值得注意的:UIATarget的delay(Number timeInterval) 方法允许你在两个操作之间做一些等待,UIALogger的logMessage( String message) 方法用来将你想打印的信息输出到日志上去,UIALogger的logPass(String message)方法指明你的测试脚本已经成功的完成测试了。
你还知道了如何访问键盘上的按钮,然后作点击操作:
app.keyboard().buttons().tap();
如何获得uiautomation的xml文件
一、软件安装
首先通过appstore下载安装Xcode开发工具,当前编写文档时最新版本为4.5.1
二、通过Xcode工具编写运行测试脚本
说明:如果是在IOS模拟器上运行测试用例,需要有被测试应用的源代码才有权限把应用安装到模拟器中,当前示例中使用了自己编写的一个简单Iphone应用,大家也可以直接在网上搜索一个开源的应用即可。
1、当你有了一个应用的源代码之后,在Xcode工具中,首先选中被测应用,然后点击菜单栏中的“Product-Profile”,则会弹出Instruments工具,在弹出的工具中选择IOS Simulator-》Automation,然后点击Profile
2、在弹出的Automation工具中选择需要测试的项目,同时在Add-》Create 添加测试脚本,点击Create后,在中间区域会出现编写测试脚本的区域,在中间添加以下脚本
//获取当前window对象
var target = UIATarget.localTarget();
var app = target.frontMostApp();
var window = app.mainWindow();
//打印除当前界面的控件数信息
target.logElementTree();
具体的API参考官方文档
***隐藏网址***
3、点击左上角的Record按钮则开始运行测试用例,运行完成后在工具的中间位置,原来编写代码的地方会出现运行结果的log日志,我们在刚才的代码中
编写了target.logElementTree(),这句API会打印出当前页面的控件信息,可以在日志中看到树形结构的控件,点击可以查看控件的一
些属性,这个API在编写代码的过程中也会比较有用。
另外如果想切换到编写代码的页面,可以点击图中红框处的进行切换。
注意:通过点击Record来运行测试用例时,代码执行完成后不会自动停止,所以需要手工的点击一下左上角的Stop按钮来停止运行。
4、录制回放功能
如果你是第一次编写自动测试脚本,可能很多API都不知道,这时候你可以先使用一下UIAutomation的录制回访功能,参考一下大概是怎么来编写测试用例的,当然你也会发现通过录制回访会有很多重复的代码,当你熟悉之后就可以不用录制回访来编写脚本了。
首先你切换到编写脚本的界面,这时候会看到中间的下方会有一个红色按钮,你点击一下就开始录制了,这时候会自动帮你在模拟器中启动起来被测应用,然后你在模拟器上继续点击操作的步骤都会被记录下来。
中间红色区域就是自动生成的代码,你可以点击代码中的箭头能看到不同的API,因为查找到一个元素可以使用不同的路径,对你属性了解API会有些帮助。
录制完成后点击红色按钮旁边的方块形停止按钮,录制就停止了,
想要运行的话还是点击左上角的Record按钮就再次运行录制结果了。
三、编写测试用例进阶篇
通过上面你应该了解了大概怎么来使用UIAutomation工具以及编写简单的测试脚本,当时编写的也不算是一个测试用例,最起码的断言操作都没有,那么这一篇我们来将一下如何来编写一个真正的测试用例。
1、元素识别
如果要编写测试用例,我们首先想到要操作的控件元素应该如何去识别找到它呢,第二节我们简单说了一下通过脚本输出控件Log是一种方式可以识别到控件,还有另外一种方式是使用设备自带的Accessibility Inspector功能
在模拟器上,你还可以激活Accessibility 的检测器。启动模拟器,找到“Settings 》 General 》 Accessibility 》 Accessibility Inspector”,然后将它设为“打开”状态。
此时在模拟器上会出现一个覆层,你进入需要测试的应用,鼠标点击相应的控件,如下图所示会看到一些信息,Label就是这个控件的id属性,Traits
就是这个控件的类型,Frame就是这个控件的位置以及大小{{36,295},{43,21}},其中第一个位置{36,295}是该控件的左上角的坐
标,{43,21}则是这个控件的宽度和高度,通过这两个参数可以算出控件的具体坐标位置。
2、编写测试用例
var testName = "FirstTest";
UIALogger.logStart(testName);
var target = UIATarget.localTarget();
var app = target.frontMostApp();
var window = app.mainWindow();
app.logElementTree();
window.tableViews().tap();
target.delay(3);
var date = window.elements();
UIALogger.logMessage( date );
if (date){
UIALogger.logPass( testName );
}
else{
UIALogger.logFail( testName );
}
上面是使用了UIAutomation自带的一些API完成了一个自动测试用例的编写,包括了元素查找以及断言操作,但是如果你编写多个测试用例的话会发现一些问题,比如一些代码会有重复,用例组织不是很好,断言操作不方便。
3、tuneup介绍
下面为大家介绍一个开源的基于UIAutomation扩展的JS库tuneup,这个js扩展库是方便大家来编写测试用例。
***隐藏网址***
如何来使用,首先你可以在电脑上新建一个测试用例目录,比如文件夹名称就叫Demo,下面可以新建一个lib子文件夹,存放需要用到的一个扩展库,你下载的tuneup目录内容可以都放到lib目录下,在demo文件夹下新建一个测试用例的js文件,测试代码中只需要把tuneup使用import引用进来就可以使用了,通过tuneup编写的测试用例如下。
#import "lib/tuneup/tuneup.js"
var target = UIATarget.localTarget();
var app = target.frontMostApp();
/* Second是测试用例的注释,可以填写用例的用途,以及编写人等信息 */
test("Second", function(target, app) {
var window = app.mainWindow();
app.logElementTree();
window.tableViews().tap();
var date = window.elements();
assertNotNull(date,"进入日期详情页面,date属性没找到!"); });
四、通过命令行运行测试用例
为了能够实现自动定时运行测试脚本,编写完成的测试用例我们希望是能够通过命令行的方式来启动运行的,那么下面我们介绍一下如何通过命令行来启动运行我们编写好的测试用例。
instruments -t /Applications/Xcode.app/Contents/Applications/Instruments.app/Contents/PlugIns/ AutomationInstrument.bundle/Contents/Resources/Automation.tracetemplate "/Users/ios/Library /Application Support/iPhone Simulator/6.0/Applications/D02EF837-94F7-457A-989A-A654FC034803 / DemoSBTableViewTest.app" -e UIASCRIPT /AutoTest/workspace/IosDemo/test.js -e UIARESULTSPATH /AutoTest/workspace/IosDemo/lib/
上面是通过命令行来运行测试用例的脚本,
-t 后面的参数为Automation.tracetemplate的路径,不用修改,Xcode4.5以后的版本路径都是这个,如果是Xcode4.5以前的路径会不一样
“/User***.app” 这个参数为被测程序的绝对路径,模拟器中安装的应用都可以在本地硬盘中找到
-e UIASCRIPT 指定执行的js脚本
-e UIARESULTSPATH 指定输出结果存放的路径
五、后续基于UIAutomation扩展需要的改进点
1、输出的用例运行结果存在给定的xml文件中, 后续需要解析xml文件,解析成testng的格式,方便后续和Jenkins等持续集成平台整合
2、查找定位元素,只能按照控件层级,一级一级往下找,使用起来有些不方便,需要再次封装一下
3、需要加入外围的一些控制,使整个自动化测试运行完全自动化,另外还需要加入一些失败重跑机制,UI的自动化一般都会存在一些不稳定的因素

更多文章:
form表单制作(为什么制作的form表单会在网页显示中多出一行)
2026年10月11日 09:10
teammate(teammate,company,partner)
2026年10月11日 06:10
javascript arraybuffer(javascript可以把base64编码转换成二进制代码吗求示例代码!)
2026年10月11日 04:00
text函数公式(excel中round和text函数的区别是什么)
2026年10月11日 03:50
google chrome打不开(chrome浏览器打不开怎么回事 浏览器打不开的处理方法)
2026年10月11日 02:00
websocket整合springboot(Springboot整合Websocket遇到的坑)
2026年10月11日 01:40
drawerlayout(android 怎样让drawerlayout设置的侧滑菜单的内容充满屏幕)
2026年10月10日 19:20
xor四位数怎么运算(单片机怎样用C语言实现4个数字间的异或)
2026年10月10日 17:50


