Instrument-Automation对IOS进行自动化测试(完整版)

    UIAutomation的功能测试代码是用Javascript编写的。通过标签和值的访问性来获得UI元素,同时完成相应的交互操作。通过一个实际的测试项目来手把手学习如何使用UIAutomation进行自动化测试。

前期准备:

  1. 申请 apple id 。
  2. 将手机的UDID加入到设备列表 (可通过iTools查看UDID)。
  3. 申请开发者证书 。
  4. 将iPhone设为开发机(Xcode>Window>Organizer>选设备>use for development)。
  5. 下载示例应用程序  TestAutomation.xcodeproj (此项目包含2个Tabbar的应用程序)。
  6. 需要修改 Target>General>Identity>Bundle Identifier改成你申请的证书对应的Identifier。
  7. 下载Identifier对应的Profiles,并安装。

第一个UIAutomation测试用例

  1. 通过USB连接手机,打开示例应用程序工程。
  2. 设置 Target > Build Settings > Code Signing > iOS Developer。
  3. 启动 Instruments(Xcode > Open Developer Tool >Instrument)。
  4. 选择 iOS > Automation >Choose。
  5. 选择 Choose Target > TestAutomation 。
  6. Scripts > Add > Create  创建新脚本。
  7. 在脚本编辑器里,输入下面的代码。
    var target = UIATarget.localTarget(); 
    var app = target.frontMostApp();
    var window = app.mainWindow(); 
    target.logElementTree();
  8. 运行这段脚本⌘R。运行完成后,可以在日志中停止它。

Instrument-Automation对IOS进行自动化测试(完整版)_第1张图片

这样完成了我们的第一个UIAutomation测试用例。


2. 访问和操作用户界面元素

     如果一个控件的Accessibility 是可以被访问的,你就可以设置和读取它的值。通过Interface Builder中,设置 Accessibility 为 Enabled。

Instrument-Automation对IOS进行自动化测试(完整版)_第2张图片

理解元素的层级结构

      在元素层级顶层是UIATarget 类,为了测试你的应用程序必须是前台活跃的程序,代码如下:

UIATarget.localTarget().frontMostApp();
      为了获得应用程序主窗口,代码如下:

UIATarget.localTarget().frontMostApp().mainWindow();
     通过从0开始的索引来访问文本框,代码如下:

var textField = UIATarget.localTarget().frontMostApp().mainWindow().textFields()[0];
     通过这个元素的名称来访问文本框,代码如下:

var textField = UIATarget.localTarget().frontMostApp().mainWindow().textFields()["User Text"];
     可以在Interface Builder中设置 UIAElement 的name属性,或通过代码方式更改

myTextField.accessibilityEnabled = YES;
myTextField.accessibilityLabel = @"User Text";
     使用logElementTree 方法显示每个元素的所有子元素集。

UIALogger.logStart("Logging element tree ...");
UIATarget.localTarget().logElementTree();
UIALogger.logPass();
该命令的输出被Automation instrument 工具捕获并日志输出,如图:

Instrument-Automation对IOS进行自动化测试(完整版)_第3张图片


3. 执行用户界面手势

     点击(Tapping)

var tabBar = UIATarget.localTarget().frontMostApp().tabBar();
var tabButton = tabBar.buttons()["First"];  
 
// Tap the tab bar 
tabButton.tap();
     可以通过屏幕的坐标,进行点击。代码如下:

UIATarget.localTarget().tap({x:100, y:200});
UIATarget.localTarget().doubleTap({x:100, y:200});
UIATarget.localTarget().twoFingerTap({x:100, y:200});
     缩放(Pinching)需要指定开始和结束坐标,指定手势需要执行的时间,代码如下:

UIATarget.localTarget().pinchOpenFromToForDuration({x:20, y:200},{x:300, y:200},2);
UIATarget.localTarget().pinchCloseFromToForDuration({x:20, y:200}, {x:300, y:200},2);
    拖拽 (Dragging)如:滚动一个列表或移动一个元素,代码如下:

UIATarget.localTarget().dragFromToForDuration({x:160, y:200},{x:160,y:400},1);
    划动 (Flicking)比较快的拖拽,代码如下:

UIATarget.localTarget().flickFromTo({x:160, y:200},{x:160, y:400});
    输入文字

var recipeName = "Unusually Long Name for a Recipe";
UITarget.localTarget().frontMostApp().mainWindow().textFields()[0].setValue(recipeName);
    导航标签

var tabBar = UIATarget.localTarget().frontMostApp().mainWindow().tabBar();
var selectedTabName = tabBar.selectedButton().name();
if(selectedTabName != "First"){
tabBar.buttons()["First"].tap();
}
    滚动到某个元素位置 可以滚动到某个不知道确切名字的位置

UIATarget.localTarget().frontMostApp().mainWindow().tableViews()[0].scrollToElementWithPredicate("name beginswith ‘ABC’");
    添加超时周期 在此周期内它会在失效之前重复的尝试执行指定的动作,动作在未超时之前返回,你的脚本可以处理它。默认周期5秒,可以通过推入一个自定义的超时周期到栈顶。代码如下:

UIATarget.localTarget().pushTimeout(2);
UIATarget.localTarget().popTimeout();

    建议不使用显式的迟延,某些场景必须使用时如下:

UIATarget.localTarget().delay(2);


   访问键盘上的按钮

app.keyboard().buttons()["Return"].tap();
    输出测试结果

var testName = "Module 001 Test";
UIALogger.logStart(testName);
//some test code
UIALogger.logPass(testName);
    增加截屏及日志输出

var testName = "Module 001 Test";
UIALogger.logStart(testName);
//some test code
UIALogger.logMessage("Starting Module 001 branch 2, validating input.");
//capture a screenshot with a specified name
UIATarget.localTarget().captureScreenWithName("SS001-2_AddedIngredient");
//more test code
UIALogger.logPass(testName);
    验证测试结果

if (cell.isValid()) {
    UIALogger.logPass(testName);
}
else {
    UIALogger.logFail(testName);
}
    处理非预期的提示框,在写自动化测试过程中,处理提示框是很难的一件事情:你已经很认真的写好了你的测试用例,然后在你准备睡觉之前将它跑起来,然后,到第二天早上,你发现你的测试用例被一个未知消息提示框给毁了。

UIATarget.onAlert = function onAlert(alert) {
    var title = alert.name();
    UIALogger.logWarning("Alert with title '" + title + "' encountered.");
    // return false to use the default handler
    return false;
}
     处理预期的提示框

UIATarget.onAlert = function onAlert(alert) {
    var title = alert.name();
    UIALogger.logWarning("Alert with title '" + title + "' encountered.");
    if (title == "The Alert We Expected") {
        alert.buttons()["Continue"].tap();
        return true;  //alert handled, so bypass the default handler
    }
    // return false to use the default handler
    return false;
}
     旋转屏幕方向

var target = UIATarget.localTarget();
var app = target.frontMostApp();
//set orientation to landscape left
target.setDeviceOrientation(UIA_DEVICE_ORIENTATION_LANDSCAPELEFT);
UIALogger.logMessage("Current orientation now " + app.interfaceOrientation());
//reset orientation to portrait
target.setDeviceOrientation(UIA_DEVICE_ORIENTATION_PORTRAIT);
UIALogger.logMessage("Current orientation now " + app.interfaceOrientation());

      多任务场景  当要测试一些多应用交互的场景时,需要将程序切到后台,等待一段时间后再返回活动状态,通过以下代码,可以模拟用户点击Home按钮。

UIATarget.localTarget().deactivateAppForDuration(10);

完整测试用例脚本

1. 在Scripts窗口里, 移除当前的脚本

2. 点击“Add > Import”然后选择TestAutomation/TestUI/Test-1.js(将下面的代码保存到这个路径)

3. 点击录制按钮 (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();
target.deactivateAppForDuration(5);
target.setDeviceOrientation(UIA_DEVICE_ORIENTATION_LANDSCAPELEFT);
UIALogger.logMessage("Current orientation is " + app.interfaceOrientation());
target.delay(1);
target.setDeviceOrientation(UIA_DEVICE_ORIENTATION_PORTRAIT);
UIALogger.logMessage("Current orientation is " + app.interfaceOrientation());
target.delay(1);

var textValue = window.staticTexts()["RecipeName"].value();
if (textValue === recipeName){
    UIALogger.logPass( testName );
}
else{
    UIALogger.logFail( testName );
}

这段脚本先启动待测程序,然后,如果第一个tab没有被选的话就切换到第一个tab,并将上面的文本框的值设成“Unusually Long Name for a Recipe”,接着收起虚拟键盘。UIALoggerlogMessage( String message) 方法用来将你想打印的信息输出到日志上去,UIALoggerlogPass(String message)方法指明你的测试脚本已经成功的完成测试了。



你可能感兴趣的:(Instrument)