Core Data Unit Testing - I don't know how to cause an error in execFetchRequest: error:

According to the NSManagedObjectContext Class Documentation ...

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

Return value

An array of objects that meet the criteria specified in the request received from the recipient and from the persistent stores associated with the coordinator of the permanent recipient store. If an error occurs, returns nil. If no objects meet the criteria specified in the query, returns an empty array.

I am trying to create a unit test for the situation "if an error occurs, returns nil."

I would like to avoid using OCMock (or a subclass of NSManagedObjectContext to override the executeFetchRequest: error :) method, because I believe this is an easy way to ensure that this method fails. While my unit test is reading ...

- (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");
}

Is there an easy way to invoke a fetch request that returns zero?

+5
source share
2 answers

I had the same puzzle. I like to keep unit test coverage at 100% whenever possible. There is no easy way to generate an organic error condition. Actually, I'm not sure that the current implementation of the 4 types of storage that come with Core Data will ever throw an error in response to executeFetchRequest: error. But, as this may happen in the future, here is what I did:

case unit test, , , executeFetchRequest: error. NSIncrementalStore, . [NSManagedObjectContext executeFetchRequest:error] [NSPersistentStoreCoordinator executeRequest:withContext:error:], [NSPersistentStore executeRequest:withContext:error:] . , "" - executeRequest:withContext:error:. , , NSPersistentStore, .

#define kErrorProneStore @"ErrorProneStore"
@interface ErrorProneStore : NSIncrementalStore


@end

@implementation ErrorProneStore

- (BOOL)loadMetadata:(NSError **)error
{
    //Required - Apple 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

Core Data ErrorProneStore , .

- (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");
}
+4

-, 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;
}
0

All Articles