У меня есть определенный юнит-тест, который вызывает у меня проблемы. Вот тест:
- (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);
});
}
Я не могу понять, почему это происходит. Когда я запускаю само приложение, все работает нормально. При запуске модульного теста кажется, что он не входит в блок завершения ... не уверен, почему?