Domanda

I have a custom view controller, on it I have a button when tapped calls a web service asynchronously using AFHTTPRequestOperation and if request return success , I push a uitableviewcontroller. This work perfectly on device and simulator. Now I want to write unit test. I am running sample unit test that xcode generates. In the unit test, I managed to get the reference to my custom uiviewcontroller via sharedapplication.delegate.window.rootviewcontroller. I can call button tapped function using performSelectorOnMainThread but success or error function of my web service request does not get fired. I call thread sleep after calling button tap event to wait still nothing fired. I suspect this is a threading issue. How can I debug this ?

È stato utile?

Soluzione

Tim's post is the general idea behind what you need to do, but it deadlocks the main thread, which can cause havoc with some APIs.

A better way to do it is to wait but keep the main thread running. There is a great example here:

IOS -NSRunLoop in XCTest: How Do I Get A Run Loop to Work in A Unit Test?

Have some sort of condition that's set when you've handled your async's completion and set up your loop that spins the run loop to end and move on when this condition is met.

Note that you might want to have a maximum time that you wait on the async test. If your async test never completes (maybe there is an error in the underlying code), you'll deadlock on the test, and that would be bad. So note the starting time of the test, and if you've been waiting longer than a certain length of time past the start time, fail the test and move on.

Altri suggerimenti

You're right that it's a threading issue. You pretty much have to keep your test "alive" until it either succeeds or fails.

Here's an example from my unit tests for my networking library.

SomeUnitTest.m

- (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];
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top