我正在测试一个方法,这个方法调用另一个迭代NSArray
个不同对象的方法,这些对象符合protocol <MNBNotificableTrabel>
。此方法检查每个对象isKindOfClass: oneClass
或otherClass是否返回给我。
for (id <MNBNotificableTravel> travel in self.travelList) {
if ([travel isGoodForNotification] && [travel notificationType] == MNBNotificableTravelTypeEditable) {
if ([notificableTravel numberOfPoisOrAssetsForNotification] < [travel numberOfPoisOrAssetsForNotification]) {
if ([travel isKindOfClass:[MNBNotificableTravelList class]] && !notificableTravel])) {
notificableTravel = travel;
} else if ([travel isKindOfClass:[MNBNotificablePoiListDraft class]]) {
notificableTravel = travel;
}
}
}
}
return notificableTravel;
}
为了测试它,我创建了一个带有mockedObjects
的假数组。我用不同的方法创建它们而不使用mockProtocol()
,因为我想区分它们。
- (MNBNotificableTravelList *)fakeTravelListGoodForNotification:(BOOL)good numberOfPois:(NSUInteger)numberOfPois type:(MNBNotificableTravelType)type travelId:(NSString *)travelId {
MNBNotificableTravelList * fakeTravel = mock([MNBNotificableTravelList class]);
[given([fakeTravel isGoodForNotification]) willReturnBool:good];
[given([fakeTravel notificationType]) willReturnInteger:type];
[given([fakeTravel numberOfPoisOrAssetsForNotification]) willReturnInteger:numberOfPois];
[given([fakeTravel travelID]) willReturn:travelId];
return fakeTravel;
}
- (MNBNotificablePoiListDraft *)fakePoiListDraftGoodForNotification:(BOOL)good numberOfPois:(NSUInteger)numberOfPois type:(MNBNotificableTravelType)type travelId:(NSString *)travelId {
MNBNotificablePoiListDraft * fakeTravel = mock([MNBNotificablePoiListDraft class]);
[given([fakeTravel isGoodForNotification]) willReturnBool:good];
[given([fakeTravel notificationType]) willReturnInteger:type];
[given([fakeTravel numberOfPoisOrAssetsForNotification]) willReturnInteger:numberOfPois];
[given([fakeTravel travelID]) willReturn:travelId];
return fakeTravel;
}
- (void)testBuildLocalNotificationShouldCallScheduleMethodFourTimes {
NSDate *installationDate = [NSDate date];
[given([self.mockUserDefaults boolForKey:mnbUserHasAuthorizedLocation]) willReturnBool:YES];
[given([self.mockUserDefaults objectForKey:mnbInstallationDateKey]) willReturn:installationDate];
[given([self.mockDateGenerator notificationDatesForScheduleLifeCycleNotifications]) willReturn:[self fakeNotificationDatesWithInstallationDate:installationDate]];
NSArray *fakeTravels = @[[self fakePoiListDraftGoodForNotification:YES numberOfPois:3 type:MNBNotificableTravelTypePublished travelId:@"1"],
[self fakePoiListDraftGoodForNotification:YES numberOfPois:3 type:MNBNotificableTravelTypeEditable travelId:@"3" ]];
MNBLifeCycleNotificationBuilder *customSut = [[MNBLifeCycleNotificationBuilder alloc] initWithUserDefaults:self.mockUserDefaults application:self.mockApplication travelList:fakeTravels];
[customSut buildLocalNotifications];
[verifyCount(self.mockApplication, times(4)) scheduleLocalNotification:instanceOf([UILocalNotification class])];
}
当我迭代此NSArray
时出现问题,如果我输入po travel
输出正确,我发现它是MNBNotificableTravelList
或MNBNotificablePoiListDraft
的模拟,但如果我输入po [travel isKindOfClass:[MNBNotificableTravelList class]]
,则输出始终为nil
。
我尝试使用[isKindOfClass:]
将回复添加到given
。但我认为这不是一个好方法,而且响应是十六进制数。
任何人都知道如何正确测试。
谢谢
答案 0 :(得分:0)
解决方案1:不要在代码中使用isKindOfClass。内省很酷,但避免使用它几乎总是更好的做法。所有条目符合的协议上的方法可用于合并逻辑,或使用像控制反转这样的模式:http://en.wikipedia.org/wiki/Inversion_of_control可以帮助您避免询问对象它们是什么类型并基于它进行切换。
解决方案2:Mocking / Overriding isKindOfClass:应该没问题。这些是模拟对象,它们应该以非标准方式运行。查看isKindOfClass:和isMemberOfClass:的NSObject文档,并在模拟对象中覆盖它们。