1

I am new to OCUnit and OCMock and would like to learn more about this testing methodology.

I am aware of OCUnit and OCMock's capabilities to create stubs generate mock object etc...

I have a particular use case that I have not been able to crack just yet.

-(bool) isGameCenterAvailable
{
    // Check for presence of GKLocalPlayer API.
    Class gcClass = (NSClassFromString(@"GKLocalPlayer"));

    // The device must be running running iOS 4.1 or later.
    bool isIPAD = [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad;
    NSString *reqSysVer = (isIPAD) ? @"4.2" : @"4.1";
    NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
    BOOL osVersionSupported = ([currSysVer compare:reqSysVer options:NSNumericSearch] != NSOrderedAscending);

return (gcClass && osVersionSupported);
}

Here are my issues with Unit Testing this:

1) NSClassFromString(@"GKLocalPlayer") is a call to foundation.h with no ability to stub this that I know of.

2) [[UIDevice currentDevice] systemVersion] are calls that are local to scope to the function. My method calls methods inside another Class (UIDevice) I would like to override their function call with stub to return a canned answer to exercise every path of this function.

Not sure if Classes can be mocked if they are instantiated within the scope of the function under test.

In addition how does one test Class methods like #1.

Is refactoring the only answer here?

narcolepsy
  • 21
  • 2

1 Answers1

1

For #1, you can create a method that checks for the GKLocalPlayer API:

-(BOOL)isGKLocalPlayerSupported {
    return (NSClassFromString(@"GKLocalPlayer")) != nil;
}

Then you can mock that method. If you create the method inside the class under test, you can use a partial mock:

-(void)testIsGameCenterAvailable {
    // create gameCenterChecker instance to test...

    id mockChecker = [OCMockObject partialMockForObject:gameCenterChecker];
    BOOL supported = YES;
    [[[mockChecker stub] andReturnValue:OCMOCK_VALUE(supported)] isGKLocalPlayerSupported];

    expect([gameCenterChecker isGKLocalPlayerSupported]).toBeTruthy();
}

Depending on your project, it might make more sense to put that in a utility class, in which case you'd mock the utility:

-(void)testIsGameCenterAvailable {
    id mockUtility = [OCMockObject mockForClass:[MyUtility class]];
    [MyUtility setSharedInstance:mockUtility];
    BOOL supported = YES;
    [[[mockUtility stub] andReturnValue:OCMOCK_VALUE(supported)] isGKLocalPlayerSupported];

    // create gameCenterChecker instance to test...

    expect([gameCenterChecker isGKLocalPlayerSupported]).toBeTruthy();
}

You could take the same approach for the system version and device:

-(NSString *)systemVersion;
-(BOOL)isIpad;
Christopher Pickslay
  • 17,523
  • 6
  • 79
  • 92