简体   繁体   中英

block callback not being called from a unit test program in IOS

I have the following setup. I have a object called "View" in which I want to unit test a method which contains two dispatch_async calls with in it.

view.m

typedef void (^onTaskCompletion)();  //defining the block

-(void) viewdidLoad
{

    onTaskCompletion block = ^{
        // callback into the block };

    [self test1:block];

}

-(void) test1:(onTaskCompletion) block
{

    //do something   
    dispatch_async(queue, ^{

    // dispatch async into serial queue & do something

        dispatch_async(dispatch_get_main_queue){

         // calling the block

         block();
        };
    }; 
}

When I run the IOS APP , the block in -(void) viewdidLoad gets called. Works perfectly fine. But the problem I have is this:

in Tests : XCTestCase (.m fie)

@property (retain) View *view;

-(void) testMyCode
{

 onTaskCompletion block = ^{
        // Never gets called.
   };
   [view test1:block];    
}

When I try to Unit test this method test1(), The block never gets called.

Note: The break point within test1() method inside the dispatch_get_main_queue() never gets hit when running in test mode but does get hit when I just run the app. Any thoughts as to why it works when the app is run normally but not when running unit tests?

The problem you are facing is that the tests continue onwards even though they are not finished. The solution is to stall the runloop until the async test if finished.

You can use this dead-simple open source macro WAIT_WHILE(<expression>, <time_limit>) found here https://github.com/hfossli/AGAsyncTestHelper

- (void)testAsyncBlockCallback
{
    __block BOOL jobDone = NO;

    [Manager doSomeOperationOnDone:^(id data) {
        jobDone = YES; 
    }];

    WAIT_WHILE(!jobDone, 2.0);
}

If you want to be able to unit test asynchronous code, you will need to wrap the dispatch_async in a class that you can mock. This class would have for example:

- (void)executeInBackground:(void(^)())task;
- (void)executeInForeground:(void(^)())task;

Then, during your tests you can mock this class. Instead of actually calling the tasks, collect the tasks when they are called, and manually have them executed in your test (not actually calling asynchronously):

- (void)executeNextBackgroundTask;
- (void)executeNextForegroundTask;

Then you can explicitly test each order of execution.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM