研究iOS的自动化测试也有些日子了,刚开始的时候,一直苦于找不到什么好的资料,只能从Apple的官网查阅相关的API文档,只可惜,Apple对开发者来说实在是不怎么友好,文档写得相当的粗略,对于初学者来说有一定的难度。
本来是打算自己动手写一篇关于iOS的UI自动化测试的入门级别的介绍性文档的,但想起来后面在具体解决一些问题的时候,收藏一篇很好的Blog,很全面地介绍了如何使用UIAutomation的JavaScript Libraries做iOS程序的自动化测试。如果作者早点看到这篇文章,应该要少走一些弯路,这里没有创意性的它他翻译成中文,希望对你们有一些帮助。
原文地址:http://blog.manbolo.com/2012/04/08/ios-automated-tests-with-uiautomation
翻译正文:
快速入门
自动化测试代码可以“在你的睡着的时候”很好地帮你测试你的应用程序。它可以让你能够快速地跟踪你程序中的回归和性能方面的问题,这样你就不用担心你新增的功能会影响到你之前已经完成开发的程序了。
随
着iOS4.0的发布,苹果公司同时发布了一个名为UIAutomation的测试框架,它可以用来在真实设备和iPhone模拟器上执行自动化测试。但
官方关于UIAutomation的文档相当的有限,在网络上也没有太多的资源可以查找的。本文将向你展示你如何将UIAutomation整合到你的工
作流程当中去。
作为基础知识的准备,你可以先看一下苹果公司关于UIAutomation的文档,另外还有一篇快速入门的介绍苹果Instruments的文档也值得看看,当然,如果你有一个免费的Apple开发者账号的话,你可以看一下WWDC 2010 - Session 306 – 使用Instruments进行用户界面自动化测试的幻灯片或者视频。
除此之外,包括在Xcode中的OCUnit测试框架也可以用来为你的应用程序编写单元测试。
1. 第一个UIAutomation测试脚本
使用iOS 模拟器
使用iOS设备
2. 处理UIAElement和元素可访问性(Accessibility)
UIAElement层次结构
模拟用户 *** 作
3. 经验分享(让你的生活变得更简单)
类库Tune-up介绍
导入外部脚本
使用强大的命令行
使用录制交互功能
当遇到问题时,加上“UIATarget.delay(1)”
4. 高级交互
处理非预期和预期的提示框(alerts)
多任务
屏幕方向
5. 总结
有用的链接
一个视频
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()
8. 重新运行这段脚本⌘R(不需要保存)。脚本跑起来后,你可以在日志打完后停止它。
赞一个!我们就这样完成了我们的第一个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. 启动测试 (⌘I)
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}}
你可以通过下面的代码来访问文本框:
var textField =
UIATarget.localTarget().frontMostApp().mainWindow().textFields()[0]
你可以选择通过从0开始的索引或者这个元素的名称来访问这个元素,例如:你也可以通过下面的代码来访问文本控件。
var textField =
UIATarget.localTarget().frontMostApp().mainWindow().textFields()["User Text"]
后一种方式更加清晰明了,应该多使用。你可以通过Interface Builder设置UIAElement的name属性,
或者通过编写代码的方式:
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()["First"]
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()["First"]
// 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()["First"].tap()
}
//-- tap on the text fiels
UIALogger.logMessage( "Tap on the text field now" )
var recipeName = "Unusually Long Name for a Recipe"
window.textFields()[0].setValue(recipeName)
target.delay( 2 )
//-- tap on the text fiels
UIALogger.logMessage( "Dismiss the keyboard" )
app.logElementTree()
app.keyboard().buttons()["return"].tap()
var textValue = window.staticTexts()["RecipeName"].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()["return"].tap()
xml.etree.ElementTree 是一个用于处理树结构的 Python 包。
它可以用于处理任何树结构的数据,但最常用于处理 XML 文档。
参考文档: http://effbot.org/zone/element.htm
Element类代表了树节点,每个树节点包含以下成员(properties):
创建树节点时,一定要指定节点名:
也可在创建时指定属性(Element.attrib):
创建节点后,可以设置 text , tail 等类成员。这些成员的初始值为 None 。
可以用 Element.append() 成员函数添加子节点:
Element类用私有成员 Element._children 存放子节点,该私有成员是一个 list 变量。
为了方便访问子节点,Element封装了下标索引函数,使用时可以把 Element 想象成一个 list
变量:
使用 xml.etree.ElementTree 包中的 tostring() 和 fromstring() 函数:
如果 tostring() 参数不指定 encoding="unicode" ,函数将返回 byte 序列。
再举一个生成 html 的例子:
添加子节点可以用 SubElement 构造函数快速实现:
XPath 全称为 Xml Path Language,即 Xml 路径语言,是一种在 Xml 文档中查找信息的语言。它提供了非常简洁的路径选择表达式,几乎所有的节点定位都可以用它来选择。
XPath 可以用于 Xml 和 Html,在爬虫中经常使用 XPath 获取 Html 文档内容。
lxml 是 Python 语言用 Xpath 解析 XML、Html文档功能最丰富的、最容易的功能模块。
节点
在 XPath 中有七种节点分别是元素、属性、文本、文档、命名空间、处理指令、注释,前3种节点为常用节点
请看下面的 Html 例子,(注:这个例子全文都需要使用)
在上面的例子中
节点关系
在 XPath中有多中节点关系分别是父节点、子节点、同胞节点、先辈节点、后代节点
在上面的例子中
用上面的 Html 文档举个例子
同样用上面的Html文档举个例子
XPath 中的谓语就是删选表达式,相当于 SQL 中的 Where 条件,谓语被嵌在 [ ] 中
lxml.etree 一个强大的 Xml 处理模块,etree 中的 ElementTree 类是一个主要的类,用于对XPath的解析、增加、删除和修改节点。
etree.parse() 函数可以解析一个网页文件还可以解析字符串, 在网页中下载的数据一般都是字符串形式的,使用 parse(StringIO(str)) 将整个页面内容解析加载构建一个 ElementTree 对象,ElementTree 可以使用 XPath 语法精准找到需要的数据。
结果:
2. 获取所有 li 标签数据
结果:
3. 获取带 class=’blank’ 属性数据
结果:
4. 属性 *** 作
结果:
5. 获取最后一个p标签数据
结果:
6. 添加子节点
7. 删除子元素
8. 遍历元素后代
结果
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)