Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/99.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 如何在单元测试中调用web服务作为uiviewcontroller的一部分?_Ios_Unit Testing_Uiviewcontroller_Performselector - Fatal编程技术网

Ios 如何在单元测试中调用web服务作为uiviewcontroller的一部分?

Ios 如何在单元测试中调用web服务作为uiviewcontroller的一部分?,ios,unit-testing,uiviewcontroller,performselector,Ios,Unit Testing,Uiviewcontroller,Performselector,我有一个自定义视图控制器,当点击时,我有一个按钮,使用AFHTTPRequestOperation异步调用web服务,如果请求返回成功,我会推一个uitableviewcontroller。这在设备和模拟器上都能很好地工作。现在我想写单元测试。我正在运行xcode生成的示例单元测试。在单元测试中,我设法通过sharedapplication.delegate.window.rootviewcontroller获得对自定义uiviewcontroller的引用。我可以使用performSelect

我有一个自定义视图控制器,当点击时,我有一个按钮,使用AFHTTPRequestOperation异步调用web服务,如果请求返回成功,我会推一个uitableviewcontroller。这在设备和模拟器上都能很好地工作。现在我想写单元测试。我正在运行xcode生成的示例单元测试。在单元测试中,我设法通过sharedapplication.delegate.window.rootviewcontroller获得对自定义uiviewcontroller的引用。我可以使用performSelectorOnMainThread调用按钮点击函数,但不会触发web服务请求的成功或错误函数。我在调用按钮点击事件后调用线程睡眠以等待仍然没有触发任何事件。我怀疑这是线程问题。我如何调试这个

你说得对,这是一个线程问题。在测试成功或失败之前,您几乎必须保持测试“活动”

下面是我的网络库单元测试中的一个示例

SomeUnitTest.m


Tim的文章是您需要做的事情背后的一般想法,但它会使主线程死锁,这可能会对某些API造成严重破坏

更好的方法是等待,但保持主线程运行。这里有一个很好的例子:

在处理异步完成时设置某种条件,并设置循环,在满足此条件时使运行循环结束并继续运行


请注意,您可能希望异步测试的等待时间最长。如果您的异步测试从未完成(可能底层代码中有错误),您将在测试中死锁,这将是不好的。因此,请注意测试的开始时间,如果您等待的时间超过了开始时间的某个时间长度,请通过测试并继续。

Colin,我将尝试此方法。我的单元测试有线程睡眠等待操作完成,正如您所说,我可能正在阻止主线程或任何线程等待成功事件。@aziz请小心,此示例不会可靠地工作:运行循环仅在处理完事件或超时时返回。在本例中,它从不超时。现在,假设您的异步任务永远不会以完全相同的模式在主运行循环上调度消息,那么此运行循环将永远不会返回。还有可能与标志发生数据竞争。死锁的可能性不能完全避免,也不能减轻。这种方法试图避免的问题是许多API同步回主线程以执行任务,但是如果单元测试已锁定等待任务完成的主线程,则会出现死锁。我倾向于认为这种方法更好,因为它承认调用可能需要主线程,但你是对的,它仍然不是完美的。谢谢Colin,这非常有效。是的,我知道可靠性问题。顺便说一句,你不想在实际测试代码中调用web服务,因为这样你就不用受控环境了。您可能需要考虑模拟web服务调用。@Abizern链接的解决方案不可靠。请阅读下面的评论为什么。@Abizern我同意我应该这样做。
- (void)signalFinished:(NSCondition *)condition
{
    [condition lock];
    [condition signal];
    [condition unlock];
}

#pragma mark - GET

- (void)testGet
{
    __block NSCondition *completed = NSCondition.new;
    [completed lock];
    __weak typeof (self) weakSelf = self;

    TSNetworkSuccessBlock successBlock = ^(NSObject *resultObject, NSMutableURLRequest *request, NSURLResponse *response) {
        XCTAssertNotNil(resultObject, @"nil result obj");
        [weakSelf signalFinished:completed]; //this
    };

    TSNetworkErrorBlock errorBlock = ^(NSObject *resultObject, NSError *error, NSMutableURLRequest *request, NSURLResponse *response) {
        XCTAssertNotNil(error, @"nil error obj");
        [weakSelf signalFinished:completed]; //or this will end the test
    };

    [[TSNetworking sharedSession] setBaseURLString:kNoAuthNeeded];
    [[TSNetworking sharedSession] performDataTaskWithRelativePath:@"something"
                                                       withMethod:HTTP_METHOD_GET
                                                   withParameters:nil
                                             withAddtionalHeaders:nil
                                                      withSuccess:successBlock
                                                        withError:errorBlock];
    [completed waitUntilDate:[NSDate distantFuture]];
    [completed unlock];
}