×

UIAutomation 自动化

前端技术网 前端技术网 发表于2023-12-07 21:09:54 浏览1173 评论0

抢沙发发表评论

一、如何使用UIAutomation进行iOS 自动化测试

1.你的第一个UIAutomation测试脚本

UIAutomation的功能测试代码是用Javascript编写的。UIAutomation和Accessibility有着直接的关系,你将用到通过标签和值的访问性来获得UI元素,同时完成相应的交互操作。

UIAutomation 自动化

下面让我们来编写我们的第一段测试代码。

使用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”。

UIAutomation 自动化

5. Instruments就已经启动好后,然后直接开始录制了。这里先停止录制,(红包按钮或者⌘R)。

6.在左边的Scripts窗口,点击“Add> Create”创建新的脚本。

7.在脚本编辑器里,输入下面的代码

var target= UIATarget.localTarget();

var app= target.frontMostApp();

var window= app.mainWindow();

target.logElementTree();

clip_image007[4]

8.重新运行这段脚本⌘R(不需要保存)。脚本跑起来后,你可以在日志打完后停止它。

clip_image009[4]

赞一个!我们就这样完成了我们的第一个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[6]

你可以通过下面的代码来访问文本框:

var textField=

UIATarget.localTarget().frontMostApp().mainWindow().textFields()[0];

你可以选择通过从0开始的索引或者这个元素的名称来访问这个元素,例如:你也可以通过下面的代码来访问文本控件。

var textField=

UIATarget.localTarget().frontMostApp().mainWindow().textFields()["User Text"];

后一种方式更加清晰明了,应该多使用。你可以通过Interface Builder设置UIAElement的name属性,

clip_image002[6]

或者通过编写代码的方式:

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("Di**iss 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();

二、如何使用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[4]

8.重新运行这段脚本⌘R(不需要保存)。脚本跑起来后,你可以在日志打完后停止它。

clip_image009[4]

赞一个!我们就这样完成了我们的第一个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[6]

你可以通过下面的代码来访问文本框:

var textField=

UIATarget.localTarget().frontMostApp().mainWindow().textFields()[0];

你可以选择通过从0开始的索引或者这个元素的名称来访问这个元素,例如:你也可以通过下面的代码来访问文本控件。

var textField=

UIATarget.localTarget().frontMostApp().mainWindow().textFields()["User Text"];

后一种方式更加清晰明了,应该多使用。你可以通过Interface Builder设置UIAElement的name属性,

clip_image002[6]

或者通过编写代码的方式:

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("Di**iss 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();

三、基于Python+UIautomation的WindowsGUI自动化测试实战

1测试需求

模拟用户操作,打开记事本进行内容输入

2测试步骤

2.1用例1

打开记事本;

窗口最大化;

输入"人生苦短,我用Python!";

关闭窗口;

不保存直接退出。

2.2用例2

打开记事本;

窗口最大化

输入:

Python之禅!

优美胜于丑陋(Python以编写优美的代码为目标)

明了胜于晦涩(优美的代码应当是明了的,命名规范,风格相似)

简洁胜于复杂(优美的代码应当是简洁的,不要有复杂的内部实现)

复杂胜于凌乱(如果复杂不可避免,那代码间也不能有难懂的关系,要保持接口简洁)

扁平胜于嵌套(优美的代码应当是扁平的,不能有太多的嵌套)

间隔胜于紧凑(优美的代码有适当的间隔,不要奢望一行代码解决问题)

可读性很重要(优美的代码是可读的)

即便假借特例的实用性之名,也不可违背这些规则(这些规则至高无上)

不要包容所有错误,除非你确定需要这样做(精准地捕获异常,不写 except:pass风格的代码)

当存在多种可能,不要尝试去猜测

而是尽量找一种,最好是唯一一种明显的解决方案(如果不确定,就用穷举法)

虽然这并不容易,因为你不是 Python之父(这里的 Dutch是指 Guido)

做也许好过不做,但不假思索就动手还不如不做(动手之前要细思量)

如果你无法向人描述你的方案,那肯定不是一个好方案;反之亦然(方案测评标准)

命名空间是一种绝妙的理念,我们应当多加利用(倡导与号召)"

END,本文到此结束,如果可以帮助到大家,还望关注本站哦!