使用OCMockito的模拟对象的isKindOfClass返回nil

时间:2015-03-16 15:13:29

标签: ios objective-c unit-testing ocmockito

我正在测试一个方法,这个方法调用另一个迭代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输出正确,我发现它是MNBNotificableTravelListMNBNotificablePoiListDraft的模拟,但如果我输入po [travel isKindOfClass:[MNBNotificableTravelList class]],则输出始终为nil

我尝试使用[isKindOfClass:]将回复添加到given。但我认为这不是一个好方法,而且响应是十六进制数。

任何人都知道如何正确测试。

谢谢

1 个答案:

答案 0 :(得分:0)

解决方案1:不要在代码中使用isKindOfClass。内省很酷,但避免使用它几乎总是更好的做法。所有条目符合的协议上的方法可用于合并逻辑,或使用像控制反转这样的模式:http://en.wikipedia.org/wiki/Inversion_of_control可以帮助您避免询问对象它们是什么类型并基于它进行切换。

解决方案2:Mocking / Overriding isKindOfClass:应该没问题。这些是模拟对象,它们应该以非标准方式运行。查看isKindOfClass:和isMemberOfClass:的NSObject文档,并在模拟对象中覆盖它们。