Методология тестирования OCUnit или OCmock для локально создаваемых переменных и переменных области видимости.

Я новичок в OCUnit и OCMock и хотел бы узнать больше об этой методологии тестирования.

Я знаю о возможностях OCUnit и OCMock создавать заглушки для создания фиктивных объектов и т. Д.

У меня есть конкретный случай использования, который я еще не смог взломать.

-(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);
}

Вот мои проблемы с модульным тестированием:

1) NSClassFromString (@ "GKLocalPlayer") является вызовом foundation.h без возможности заглушить это, о чем я знаю.

2) [[UIDevice currentDevice] systemVersion] - это вызовы, локальные для области действия функции. Мой метод вызывает методы внутри другого класса (UIDevice). Я бы хотел переопределить вызов их функции с помощью заглушки, чтобы вернуть стандартный ответ, чтобы использовать каждый путь этой функции.

Не уверен, что классы можно смоделировать, если они создаются в рамках тестируемой функции.

Кроме того, как можно тестировать методы класса, такие как #1.

Является ли рефакторинг единственным ответом здесь?

1 ответ

Для #1 вы можете создать метод, который проверяет GKLocalPlayer API:

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

Тогда вы можете издеваться над этим методом. Если вы создаете метод внутри тестируемого класса, вы можете использовать частичный макет:

-(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();
}

В зависимости от вашего проекта, может иметь смысл поместить это в служебный класс, и в этом случае вы будете издеваться над утилитой:

-(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();
}

Вы можете использовать тот же подход для версии системы и устройства:

-(NSString *)systemVersion;
-(BOOL)isIpad;
Другие вопросы по тегам