Проблема модульного теста с использованием OCMock (Objective- C) - PullRequest
0 голосов
/ 07 февраля 2020

У меня есть определенный юнит-тест, который вызывает у меня проблемы. Вот тест:

- (void)testFullFailContentPackage
{
    id mock = [self fullMockFailContentPackage];

    XCTestExpectation *expectation = [self expectationWithDescription:@"Media Fails for Playback"];
    BMAxisMetadataService *metadataService = [[BMAxisMetadataService alloc] initWithCapiNetworking:mock];
    BMLocationInformation *location = [[BMLocationInformation alloc] init];
    CLLocation *geoLoc = [[CLLocation alloc] initWithLatitude:43.6532 longitude:79.3832];
    location.geoLocation = geoLoc;
    location.postalCode = @"M5V";

    [metadataService playbackDetailsForContent:kValidContentId location:location completion:^(NSError * _Nullable error, BOOL success, id<BMPlayerMetadata>  _Nullable metadata, id<BMPlaybackInformation>  _Nullable playbackInformation, BOOL blackoutInEffect, UIImage * _Nullable blackoutImage) {
        if (playbackInformation != nil)
        {
            XCTFail(@"This test shouldn't pass as the media has error");
        }
        else
        {
            [expectation fulfill];
            XCTAssertTrue(1);
        }
    }];

    [self waitForExpectationsWithTimeout:kTestTimeOutConst handler:nil];
}

Код для fullMockFailContentPackage находится здесь:

- (id)fullMockFailContentPackage
{
    id mock = [OCMockObject mockForClass:[BMCapiNetworking class]];

    [[[mock expect] andDo:^(NSInvocation *manifestLoadInvocation) {
        BMLoadDirectManifestFileCompletion loadManifestCompletion = nil;
        NSInteger manifestArgument = (NSInteger)manifestLoadInvocation.methodSignature.numberOfArguments - 1;
        [manifestLoadInvocation getArgument:&loadManifestCompletion atIndex:manifestArgument];
        loadManifestCompletion(true, kDirectManifestURL, nil);
    }] loadDirectManifestURLWithId:[kValidContentId integerValue] contentPackageId:[kValidContentPackageId intValue] deviceId:[OCMArg any] location:[OCMArg any] quality:BMAxisVideoQualityDefault completion:[OCMArg any]];

    [[[mock expect] andDo:^(NSInvocation *cpInvocation) {
        NSError *error = [NSError errorWithDomain:@"TestDomain" code:400 userInfo:nil];

        BMContentPackageCompletion completion = nil;
        NSInteger cpArgumentIndex = (NSInteger)cpInvocation.methodSignature.numberOfArguments - 1;
        [cpInvocation getArgument:&completion atIndex:cpArgumentIndex];
        completion(nil, error);
    }] loadContentPackageWithId:[kValidContentPackageId intValue] contentId:[kValidContentId intValue] geo:[OCMArg any] postalcode:[OCMArg any] completion:[OCMArg any]];

    [[[mock expect] ignoringNonObjectArgs] setIsGeoLocationAuthorized:0];

    [[[mock expect] andDo:^(NSInvocation *cpInvocation) {
        BMContentPackage *contentPackage = OCMPartialMock([BMContentPackage new]);
        contentPackage.objectId = kValidContentPackageId;

        BMContentPackageCompletion completion = nil;
        NSInteger cpArgumentIndex = (NSInteger)cpInvocation.methodSignature.numberOfArguments - 1;
        [cpInvocation getArgument:&completion atIndex:cpArgumentIndex];
        completion(contentPackage, nil);
    }] loadContentPackageForPlaybackLanguage:[kValidContentId intValue] completion:[OCMArg any]];

    [[[mock expect] andDo:^(NSInvocation *mediaInvocation) {
        BMMedia *mediaMock = OCMPartialMock([BMMedia new]);
        mediaMock.objectId = kValidMediaId;
        mediaMock.name = @"CTV";

        BMMediaCompletion completion = nil;
        NSInteger mediaArgument = (NSInteger)mediaInvocation.methodSignature.numberOfArguments - 1;
        [mediaInvocation getArgument:&completion atIndex:mediaArgument];
        completion(mediaMock, nil);
    }] loadMediaWithId:[kValidMediaId intValue] completionBlock:[OCMArg any]];

    [[[mock expect] andDo:^(NSInvocation *invocation) {
        BMContent *contentMock = OCMPartialMock([BMContent new]);
        contentMock.objectId = kValidContentId;
        contentMock.name = @"CTV Toronto";

        BMMedia *media = OCMPartialMock([BMMedia new]);
        media.objectId = kValidMediaId;
        [contentMock setMedia:media];

        BMContentPackage *contentPackage = OCMPartialMock([BMContentPackage new]);
        contentPackage.objectId = kValidContentPackageId;
        [contentMock setContentPackages:[NSArray arrayWithObjects:contentPackage, nil]];

        BMContentCompletion completionBlock = nil;
        NSInteger argumentIndex = (NSInteger)invocation.methodSignature.numberOfArguments - 1;
        [invocation getArgument:&completionBlock atIndex:argumentIndex];
        completionBlock(contentMock, nil);
    }] loadContentWithId:[kValidContentId intValue] completion:[OCMArg any]];

    return mock;
}

Этот модульный тест, по-видимому, не вводит блок завершения в строке fetchLocation во фрагменте кода ниже :

- (void)continuePlaybackWithData:(BMContent *)content withContentId:(NSString *)contentId contentPackage:(BMContentPackage *)contentPackage location:(BMLocationInformation *)location completion:(BMPlayerMetadataComponentBlock)completion
{
    NSInteger contentID = [contentId integerValue];
    self.networkingInstance.isGeoLocationAuthorized = NO;
    BMAxisPlaybackInformation *playbackInfo = [[BMAxisPlaybackInformation alloc] init];
    NSMutableArray *errors = [NSMutableArray array];

    if (content.media == nil || contentPackage == nil)
    {
        BMLogDebug(@"The content object has nothing in it's media object or the content package itself has come back nil.");
        // TODO: what is this error supposed to represent?!
        NSError *error = [NSError errorWithDomain:kCAPIDomain code:400 userInfo:nil];
        completion(error, NO, nil, nil, NO, nil);
        return;
    }

    dispatch_group_t serviceGroup = dispatch_group_create();

    //Run these calls in the background thread since we don't want to block UI
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, kNilOptions), ^{

        dispatch_group_enter(serviceGroup);
        [self mediaPlaybackWithMedia:content.media completionBlock:^(BMMedia * _Nullable media, NSError * _Nullable mediaError) {
            if (mediaError != nil)
            {
                [errors addObject:[self friendlyErrorFromError:mediaError]];
                BMLogDebug(@"mediaError: %@", mediaError.localizedDescription);
            }
            else if (media != nil)
            {
                self.metadata.seriesName = media.name;
                self.metadata.adServerName = media.DFPName;
            }
            dispatch_group_leave(serviceGroup);
        }];

        dispatch_group_enter(serviceGroup);

        [self.locationManager fetchLocation:^(CLLocation *geoLocation, NSError *geoFetchError) {
            if (geoFetchError)
            {
                [errors addObject:[self friendlyErrorFromError:geoFetchError]];
            }
            else if (geoLocation)
            {
                location.geoLocation = geoLocation; // the user's geo location coordinates
                self.networkingInstance.isGeoLocationAuthorized = YES;
            }

            if (contentPackage)
            {
                self.metadata.contentPackageName = contentPackage.name;
                self.metadata.contentPackageId = contentPackage.objectId;
                NSInteger contPackageId = contentPackage.objectId.integerValue;
                [self.networkingInstance loadContentPackageWithId:contPackageId contentId:contentID geo:nil postalcode:location.postalCode completion:^(BMContentPackage * _Nullable contentPackageDetails, NSError * _Nullable contentPackageError) {

                    if (contentPackageError != nil)
                    {
                        [errors addObject:contentPackageError];
                    }

                    self.metadata.chapters = [self loadChaptersFromContentPackage:contentPackageDetails];
                    self.metadata.contentPackageId = contentPackageDetails.objectId;
                    self.metadata.CDNDomain = contentPackageDetails.manifestHost;
                    self.metadata.videoDuration = [contentPackageDetails.duration integerValue];

                    if (contentPackageDetails.constraints.security.type != nil)
                    {
                        self.metadata.securityType = contentPackageDetails.constraints.security.type;
                    }
                    else
                    {
                        self.metadata.securityType = nil;
                    }

                    NSNumber *numPromptTime = contentPackageDetails.promptTime;
                    if (numPromptTime.boolValue)
                    {
                        self.metadata.promptTime = numPromptTime;
                    }
                    else
                    {
                        self.metadata.promptTime = @(self.configSettings.upNextStartTime);
                    }

                    playbackInfo.hasClosedCaptioning = contentPackageDetails.hasClosedCaptions;
                    BMLogDebug(@"Content has closed captioning: %@", playbackInfo.hasClosedCaptioning ? @"YES" : @"NO");

                    [self updateMetadataPromptTime:self.metadata fromPackage:contentPackageDetails];

                    dispatch_group_leave(serviceGroup);
                }];

                dispatch_group_notify(serviceGroup, dispatch_get_main_queue(), ^{
                    //So after our loadMedia and loadContentPackage calls, if we got errors, no reason to continue
                    if (errors.count > 0)
                    {
                        completion(errors.firstObject, NO, nil, nil, NO, nil);
                        return;
                    }

                    [self loadManifestAndPlayback:contentId
                                    contentPackage:contentPackage
                                          location:location
                                      playbackInfo:playbackInfo
                                   completionBlock:^(BOOL contentAvailable, NSError *playbackError, BOOL blackoutInEffect, UIImage *blackoutImage) {
                                       dispatch_async(dispatch_get_main_queue(), ^{
                                           if (playbackError != nil)
                                           {
                                               NSError *checkManifestError = [self friendlyErrorFromError:playbackError];
                                               completion(checkManifestError, NO, nil, nil, NO, nil);
                                           }
                                           else if (blackoutInEffect && blackoutImage != nil)
                                           {
                                               completion(nil, YES, self.metadata, playbackInfo, YES, blackoutImage);
                                           }
                                           else if (contentAvailable)
                                           {
                                               completion(nil, YES, self.metadata, playbackInfo, NO, nil);
                                           }
                                       });
                                   }];
                });
            }
            else
            {
                BMLogDebug(@"There is no content package for the selected playback language.");
                NSError *error = [NSError errorWithDomain:kCAPIDomain code:400 userInfo:nil];
                completion(error, NO, nil, nil, NO, nil);
                return;
            }

            dispatch_group_leave(serviceGroup);
        }];

        dispatch_group_enter(serviceGroup);
    });
}

Я не могу понять, почему это происходит. Когда я запускаю само приложение, все работает нормально. При запуске модульного теста кажется, что он не входит в блок завершения ... не уверен, почему?

...