核心数据单元测试 - 不确定如何在executeFetchRequest中触发错误情况:错误:

时间:2012-02-21 17:26:29

标签: ios unit-testing core-data

根据NSManagedObjectContext Class Documentation ...

- (NSArray *)executeFetchRequest:(NSFetchRequest *)request error:(NSError **)error
  

返回值

     

一组对象,它们满足从接收者和与接收者持久性存储协调器关联的持久存储中获取的请求所指定的条件。如果发生错误,则返回nil。如果没有对象符合请求指定的条件,则返回一个空数组。

我正在尝试为情况创建单元测试“如果发生错误,则返回nil。”

我想远离使用OCMock(或子类化NSManagedObjectContext来覆盖executeFetchRequest:error:方法),因为我认为有一种简单的方法可以确保此方法失败。到目前为止,我的单元测试都是......

- (void)testReportingCoreDataErrorToDelegate
{
    NSManagedObjectContext *badContext = [[NSManagedObjectContext alloc] init];

    [bcc setManagedObjectContext:badContext];
    [bcc fetchFromCoreData];
    STAssertTrue([mockDelegate didReceiveCoreDataError], @"This never asserts, it fails because the fetch request couldn't find an entity name - i.e. no managed object model");
}

是否有一种简单的方法可以触发返回nil的获取请求?

2 个答案:

答案 0 :(得分:4)

我有同样的难题。我希望尽可能将单元测试覆盖率保持在100%。没有简单的方法来生成有机错误条件。事实上,我不确定Core Data附带的4种商店类型的当前实现是否会永远触发错误以响应executeFetchRequest:error。但正如将来可能发生的那样,我就是这样做的:

我有一个单元测试用例文件,专门用于验证我的类如何处理由executeFetchRequest填充的错误:error。我定义了一个NSIncrementalStore的子类,它总是在实现文件中的请求期间产生错误。 [NSManagedObjectContext executeFetchRequest:error][NSPersistentStoreCoordinator executeRequest:withContext:error:]处理[NSPersistentStore executeRequest:withContext:error:],在所有商店处理executeRequest:withContext:error:。当您移动到协调器时,您可能会注意到“fetch”一词下降 - 保存和获取请求由同一方法处理 #define kErrorProneStore @"ErrorProneStore" @interface ErrorProneStore : NSIncrementalStore @end @implementation ErrorProneStore - (BOOL)loadMetadata:(NSError **)error { //Required - Apple's documentation claims you can omit setting this, but I had memory allocation issues without it. NSDictionary * metaData = @{NSStoreTypeKey : kErrorProneStore, NSStoreUUIDKey : @""}; [self setMetadata:metaData]; return YES; } -(void)populateError:(NSError **)error { if (error != NULL) { *error = [[NSError alloc] initWithDomain:NSCocoaErrorDomain code:NSPersistentStoreOperationError userInfo:nil]; } } - (id)executeRequest:(NSPersistentStoreRequest *)request withContext:(NSManagedObjectContext *)context error:(NSError **)error { [self populateError:error]; return nil; } - (NSIncrementalStoreNode *)newValuesForObjectWithID:(NSManagedObjectID *)objectID withContext:(NSManagedObjectContext *)context error:(NSError **)error { [self populateError:error]; return nil; } - (id)newValueForRelationship:(NSRelationshipDescription *)relationship forObjectWithID:(NSManagedObjectID *)objectID withContext:(NSManagedObjectContext *)context error:(NSError **)error { [self populateError:error]; return nil; } - (NSArray *)obtainPermanentIDsForObjects:(NSArray *)array error:(NSError **)error { [self populateError:error]; return nil; } @end 。因此,通过定义NSPersistentStore,我将获得覆盖保存错误和获取请求的测试,该NSPersistentStore将始终响应保存和错误提取。

- (void)testFetchRequestErrorHandling
{
    NSManagedObjectModel * model = [NSManagedObjectModel mergedModelFromBundles:nil];

    [NSPersistentStoreCoordinator registerStoreClass:[ErrorProneStore class]
                                        forStoreType:kErrorProneStore];

    NSPersistentStoreCoordinator * coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];


    NSManagedObjectContext * context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
    [context setPersistentStoreCoordinator:coordinator];
    [coordinator addPersistentStoreWithType:kErrorProneStore
                              configuration:nil
                                        URL:nil
                                    options:nil
                                      error:nil];

    NSFetchRequest * request = [NSFetchRequest fetchRequestWithEntityName:@"AValidEntity"];

    NSError * error;
    [context executeFetchRequest:request
                           error:&error];

    STAssertNotNil(error, @"Error should always be nil");
}

现在,您可以使用ErrorProneStore构造Core Data堆栈,并保证您的获取请求将返回nil并填充error参数。

{{1}}

答案 1 :(得分:0)

在我看来,使用OCMock要容易得多。

- (void)testCountForEntityFetchError {
  id mockContext =[OCMockObject partialMockForObject:self.context];

  [[[mockContext stub] andCall:@selector(stubbedExecuteFetchRequest:error:) onObject:self] countForFetchRequest:OCMOCK_ANY error:[OCMArg setTo:nil]];

  // Your code goes here
}

- (NSArray *)stubbedExecuteFetchRequest:(NSFetchRequest *)request error:(NSError **)error {
  *error = [NSError errorWithDomain:@"CRTest" code:99 userInfo:nil];
  return nil;
}