Методология тестирования 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;