Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When making unit tests for objective C, how do you test blocks?

I have a function (internally uses ASIHTTPRequest) which calls a block with the result:

[Http get:@"http://api.geonames.org/postalCodeLookupJSON"
   params:params cacheMins:0 complete:^(NSDictionary *response, BOOL success) {
       STAssertTrue(success, @"JSON retrieved OK");
       STFail(@"blah");
}];

I want to test the above, but it seems the test doesn't get called.

How can i ensure that the test waits till the block is called?

-edit-

Of course i don't recommend to do this in the main app in the gui thread, in this particular situation it is only for a unit test.

like image 279
Chris Avatar asked Apr 13 '11 02:04

Chris


People also ask

How do you structure unit tests?

A typical unit test contains 3 phases: First, it initializes a small piece of an application it wants to test (also known as the system under test, or SUT), then it applies some stimulus to the system under test (usually by calling a method on it), and finally, it observes the resulting behavior.

How do you write a unit test case in swift 5?

To create new unit case in iOS, go to File -> New -> File, and then select Unit Test Case Class. Doing so creates a template just like the one you got with your project. In our case, we want to name the file to correspond with the new Pokemon-related data structures we have introduced.


2 Answers

Found a solution:

Wait for code to finish execution

Eg:

__block int done=0;
[Http get:@"http://api.geonames.org/postalCodeLookupJSON"
   params:params cacheMins:0 complete:^(NSDictionary *response, BOOL success) {
       STAssertTrue(success, @"JSON retrieved OK");
       NSArray *postalcodes = [response objectForKey:@"postalcodes"];
       NSDictionary *first = [postalcodes objectAtIndex:0];
       NSString *adminName1 = [first objectForKey:@"adminName1"];
       STAssertTrue([adminName1 isEqualToString:@"New South Wales"], @"NSW");
       done=1;
}];

// https://stackoverflow.com/questions/3615939/wait-for-code-to-finish-execution
while (!done) {
    // This executes another run loop.
    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
    // Sleep 1/100th sec
    usleep(10000);
}
like image 84
Chris Avatar answered Nov 12 '22 18:11

Chris


Not sure where I found this, but there's a better way that doesn't use sleeps:

while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true) && !placeMarkUpdated){};

here it is in context, testing a reverse geocoding request:

__block BOOL placeMarkUpdated = NO;

[geocoder reverseGeocodeLocation:location completionHandler:^(NSArray *placemarks, NSError *error) {
    if (placeMarkUpdated == NO) {
        placeMarkUpdated = YES;
        CLPlacemark *placemark = [placemarks objectAtIndex:0];
        address = [Address addressFromPlacemark:placemark];
    }
}];

while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true) && !placeMarkUpdated){};

Sleeps suck cause they slow down the build (I know 5s doesn't sound bad, but consider the old story: guy goes to doctor cause his knees hurt from running, Doctor says 'get up on the table' and taps his knee and says 'does that hurt?' guy says 'no,' doctor: 'it would if I did it 10K times...'

like image 43
Rob Avatar answered Nov 12 '22 19:11

Rob