【问题标题】:Issuing a synchronous HTTP GET request or invoking shell script in JavaScript from iOS UIAutomation从 iOS UIAutomation 发出同步 HTTP GET 请求或在 JavaScript 中调用 shell 脚本
【发布时间】:2011-05-31 18:23:37
【问题描述】:

我正在尝试使用 Apple 的 UIAutomation 为具有服务器端组件的 iOS 应用程序编写单元测试。为了在各种状态下设置测试服务器(以及模拟两个客户端通过我的服务器进行通信),我想从我的基于 javascript 的测试中发出 HTTP 获取请求。

谁能提供一个示例,说明如何直接从 UIAutomation javascript 测试中发出 HTTP GET 请求,或者如何从我的 UIAutomation javascript 测试中调用 shell 脚本?

FWIW,UIAutomation 运行时中缺少所有浏览器可用的大多数核心对象。例如,尝试使用 XMLHTTPRequest,您将收到一个异常报告,报告它找不到变量。

谢谢!

【问题讨论】:

    标签: javascript iphone ios integration-testing ios-ui-automation


    【解决方案1】:

    伙计们,

    我能够通过向 iOS 客户端发送 HTTP 请求以处理并在 UIAlertView 中返回结果来解决此问题。请注意,所有 iOS 代码修改都包含在 #if DEBUG 条件编译指令中。

    首先,将您的客户端设置为在设备抖动时发送通知。 Read this post for more information

    接下来,在您的 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, 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 或您的用户可以手动将 URL 输入到此 UITextField 中。当您再次摇动设备时,如果文本以“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 */)
    

    我已经成功使用这种方法几个星期了。

    【讨论】:

    • 看起来很丑陋。但它应该工作:)。但我正在寻找允许在不更改 iOS 代码的情况下执行此操作的工具...
    • 如果你找到了,我全都听好了。还有corner.squareup.com/2011/07/ios-integration-testing.html,但它显然使用了未记录的 API。太糟糕了,Apple 的解决方案太烂了。
    【解决方案2】:

    试试performTaskWithPathArgumentsTimeout

    UIATarget.host().performTaskWithPathArgumentsTimeout("/usr/bin/curl", "http://google.com", 30);
    

    【讨论】:

      【解决方案3】:

      只是一个小的修正。建议使用 UIATarget.host().performTaskWithPathArgumentsTimeout 的答案是在 iOS 5.0+ 中对 URL 发出请求的简单方法,但示例的语法不正确。这是进行此调用的正确方法:

      UIATarget.host().performTaskWithPathArgumentsTimeout("/usr/bin/curl", ["http://google.com"], 30);
      

      “args”参数周围的“[”很重要,如果忘记括号,测试将终止,并出现类似于以下的异常:

      错误:-[__NSCFString count]:无法识别的选择器发送到实例

      这是一个完整的示例,它访问了 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);
      

      【讨论】:

        【解决方案4】:

        +1 创造性地使用“shake()”。但是,对于某些项目,尤其是那些实际使用抖动功能的项目,这不是一个选项。

        跳出框框思考。使用其他东西(Python、Ruby、node.js、bash+wget 等)进行获取。然后,您可以使用预先准备好的响应并通过将动态生成的 json 有效负载作为“样本数据”包含到测试中来即时自动生成 ui-test.js。然后你只需执行测试。

        在我看来,测试就是测试,别管它。您正在使用的测试数据,如果它是动态的,它应该与测试本身分开。通过以这种方式获取/生成 JSON,并从测试中引用它,您可以随时更新 JSON,无论是在每次测试之前,还是在您知道服务器已更新时的设定时间间隔内。我不确定您是否希望在测试运行时生成它,这似乎会产生问题。将它提升到一个新的水平,您可以花哨并使用函数来计算应该基于其他值的值,并将它们公开为数据的“动态属性”,而不是在测试中进行数学运算,但在那我认为讨论更多的是学术性的,而不是实践性的。

        【讨论】:

          【解决方案5】:

          Apple 最近更新了 UIAutomation,在运行 Instruments 实例的 Host 上为 performing a task 添加了一个新的 UIAHost 元素。

          【讨论】:

            猜你喜欢
            • 2018-01-31
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-09-29
            • 1970-01-01
            • 1970-01-01
            • 2014-08-15
            • 1970-01-01
            相关资源
            最近更新 更多