从iOS UIAutomation发出同步HTTP GET请求或在JavaScript中调用Shell脚本

问题描述

| 我正在尝试使用Apple的UIAutomation为具有服务器端组件的iOS应用程序编写单元测试。为了在各种状态下设置测试服务器(以及模拟通过我的服务器进行通信的两个客户端),我想在基于JavaScript的测试中发出HTTP get请求。 谁能提供一个示例,说明如何直接从UIAutomation javascript测试内发出HTTP GET请求,或者如何从UIAutomation javascript测试内调用Shell脚本? FWIW,UIAutomation运行时中缺少所有浏览器提供的大多数核心对象。例如,尝试使用XMLHTTPRequest,您将收到一个异常报告,指出它找不到该变量。 谢谢!     

解决方法

        民间, 通过将HTTP请求发送到iOS客户端来处理并在UIAlertView中返回结果,我能够解决此问题。请注意,所有iOS代码修改都包装在#if DEBUG条件编译指令中。 首先,将您的客户端设置为在设备震动时发出通知。阅读这篇文章以获取更多信息。 接下来,在您的iOS主应用程序委托中添加以下代码:
[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(deviceShakenShowDebug:)
                                             name:@\"DeviceShaken\" 
                                           object:nil];
然后添加如下所示的方法:
- (void) deviceShakenShowDebug:(id)sender
{
    if (!self.textFieldEnterDebugArgs)
    {
        self.textFieldEnterDebugArgs = [[[UITextField alloc] initWithFrame:CGRectMake(0,260.0,25.0)] autorelease];
        self.textFieldEnterDebugArgs.accessibilityLabel = @\"AlertDebugArgsField\";
        self.textFieldEnterDebugArgs.isAccessibilityElement = YES;
        [self.textFieldEnterDebugArgs setBackgroundColor:[UIColor whiteColor]];
        [self.tabBarController.selectedViewController.view addSubview:self.textFieldEnterDebugArgs];
        [self.tabBarController.selectedViewController.view bringSubviewToFront:self.textFieldEnterDebugArgs];
    }
    else
    {
        if ([self.textFieldEnterDebugArgs.text length] > 0)
        {
            if ([self.textFieldEnterDebugArgs.text hasPrefix:@\"http://\"])
            {
                [self doDebugHttpRequest:self.textFieldEnterDebugArgs.text];    
            }
        }
    }
}

- (void)requestDidFinishLoad:(TTURLRequest*)request
{
        NSString *response = [[[NSString alloc] initWithData:((TTURLDataResponse*)request.response).data 
                                                    encoding:NSUTF8StringEncoding] autorelease];

        UIAlertView *resultAlert = 
            [[[UIAlertView alloc] initWithTitle:NSLocalizedString(@\"Request Loaded\",@\"\")
                                       message:response
                                      delegate:nil
                             cancelButtonTitle:NSLocalizedString(@\"OK\",@\"\")
                             otherButtonTitles:nil] autorelease];
        resultAlert.accessibilityLabel = @\"AlertDebugResult\";
        [resultAlert show];
}
摇动之后,此代码会将UITextField添加到最顶视图的控制器中,在任何导航栏或其他UI元素的正上方。 UIAutomation或您的用户可以在此UITextField中手动输入URL。当您再次摇动设备时,如果文本以\“ http \”开头,它将在代码中发出HTTP请求(练习使读者实现doDebugHttpRequest)。 然后,在我的UIAutomation JavaScript文件中,定义了以下两个函数:
function httpGet(url,delayInSec) {
  if (!delayInSec) delay = 1;
  var alertDebugResultSeen = false;
  var httpResponseValue = null;

  UIATarget.onAlert = function onAlert(alert) {    
    httpResponseValue = alert.staticTexts().toArray()[1].name();
    alert.buttons()[0].tap();
    alertDebugResultSeen = true;
  }

  var target = UIATarget.localTarget();
  var application = target.frontMostApp();
  target.shake(); // bring up the input field
  application.mainWindow().textFields()[\"AlertDebugArgsField\"].setValue(url);
  target.shake(); // send back to be processed
  target.delay(delayInSec);
  assertTrue(alertDebugResultSeen);
  return httpResponseValue;
}

function httpGetJSON(url,delayInSec) {
  var response = httpGet(url,delayInSec);
  return eval(\'(\' + response + \')\');
}
现在,在我的javascript文件中,我可以调用
httpGet(\'http://localhost:3000/do_something\')
它将执行一个HTTP请求。如果我想从服务器返回JSON数据,请致电
var jsonResponse = httpGetJSON(\'http://localhost:3000/do_something\')
如果我知道这将是一个长期运行的电话,我打电话
var jsonResponse = httpGetJSON(\'http://localhost:3000/do_something\',10 /* timeout */)
我已经成功地使用了这种方法已有几个星期了。     ,        尝试performTaskWithPathArgumentsTimeout
UIATarget.host().performTaskWithPathArgumentsTimeout(\"/usr/bin/curl\",\"http://google.com\",30);
    ,        只是一个小的更正。建议使用UIATarget.host()。performTaskWithPathArgumentsTimeout的答案是在iOS 5.0+中对URL进行请求的简便方法,但是示例的语法不正确。这是进行此调用的正确方法:
UIATarget.host().performTaskWithPathArgumentsTimeout(\"/usr/bin/curl\",[\"http://google.com\"],30);
\“ args \”参数周围的\“ [\”很重要,并且如果忘记括号,该测试将以类似于以下的异常终止: 错误:-[__ NSCFString计数]:无法识别的选择器已发送到实例 这是一个完整的示例,可访问google.com并记录所有输出:
var result = UIATarget.host().performTaskWithPathArgumentsTimeout(\"/usr/bin/curl\",[\"http://www.google.com\"],30);

UIALogger.logDebug(\"exitCode: \" + result.exitCode);

UIALogger.logDebug(\"stdout: \" + result.stdout);

UIALogger.logDebug(\"stderr: \" + result.stderr);
    ,        +1以创造性地使用\“ shake()\”。但是,对于某些项目,尤其是那些实际使用摇动功能的项目,这不是一个选择。 创造性思考。使用其他内容(Python,Ruby,node.js,bash + wget等)进行提取。然后,您可以使用预先设置的响应,并通过将动态生成的json有效内容作为“样本数据”包含到测试中来动态地自动生成ui-test.js。然后,您只需执行测试。 在我看来,测试就是测试,别说了。您正在使用的测试数据,如果是动态的,则应与测试本身分开。通过以这种方式获取/生成JSON并从测试中引用它的方式,您可以随时随地更新JSON,可以在每次测试之前立即更新,也可以在固定的时间间隔(例如您知道服务器已更新)进行更新。我不确定您是否要在测试运行时生成它,这似乎会产生问题。将其带入一个新的水平,您可能会发现并使用函数来计算应该基于其他值的值,并将它们显示为数据的“动态属性”,而不是将数学作为测试的一部分,但是在这一点上,我认为讨论更多是学术性的而不是实践性的。     ,        Apple最近对ѭ9进行了更新,以包括一个新的for10元素,用于在运行正在执行测试的Instruments实例的主机上执行任务。