Bagusflyer
Bagusflyer

Reputation: 12915

Can only start XCTest on certain condition

I encountered an issue when I'm writing XCTestCase. I'm working on a client/server application. User can only start to use the system when the application login to the server which is automatically done in:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

     // connect to server and login
     [mySys login:^{ 

         login = YES;
     }];

}

All my test case can only be run when the login flag is YES. Because the login may take sometimes. That means I have to let all my tests to wait at least for a period of time (for example, 30 second). It's something like this:

-(void)setUp
{
    // Need to be blocked here until timeout !!!
    AppDelegate* app = [UIApplication sharedApplication].delegate;
    if ( app.login )
    {
        // quit from the block !!!
    }
}

What could be the best strategy to implement this? Thanks

Upvotes: 0

Views: 645

Answers (2)

Bagusflyer
Bagusflyer

Reputation: 12915

Thanks for Jeff's answer. I learned a lot from the video. After my serious consideration, I'm still going to test my Rest API in unit test. Mainly because I'm the one who work on the Rest API. I want to test my client and server at the same time. I'll definitely go with Jeff's idea if I'm working on a big project and the models are more complicated.

Finally I'll show my solution: (Wait for a operation finished before starting the test). The idea is to write a base class who inherits from XCTextCase. And I'm using NSNotification to broadcast the login event.

- (void)setUp
{
    [super setUp];

    AppDelegate* app = [UIApplication sharedApplication].delegate;
    if ( ![app isLogin] )
    {
        [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(onLogin:) name:NOTIFICATION_LOGIN object:nil];

        NSDate* loopUntil = [NSDate dateWithTimeIntervalSinceNow:10];
        NSDate *dt = [NSDate dateWithTimeIntervalSinceNow:0.1];

        while (!self.bCheckIn && [loopUntil timeIntervalSinceNow] > 0) {
            [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
                             beforeDate:dt];

        }
    }
}

- (void)tearDown
{
    [[NSNotificationCenter defaultCenter]removeObserver:self name:NOTIFICATION_LOGIN object:nil];
    [super tearDown];
}

- (void)onLogin:(NSNotification *)notification
{
    self.bLogin = YES;
}

Upvotes: 0

Tim
Tim

Reputation: 9042

Create a mock login, that doesn't actually call to the server, and takes a completion block with the login already set to YES. I recommend eBay's tech talk on TDD, it covers this very scenario.

I recommend watching the whole video, but here is a link to the specific part: https://www.youtube.com/watch?v=_CeWMxzB1SI#t=1805

Upvotes: 2

Related Questions