2012-02-21 9 views
5

Según NSManagedObjectContext Class Documentation ...Core Unidad de Pruebas de datos - Sin saber cómo activar caso de error en executeFetchRequest: Error:

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

Return Value

An array of objects that meet the criteria specified by request fetched from the receiver and from the persistent stores associated with the receiver’s persistent store coordinator. If an error occurs, returns nil. If no objects match the criteria specified by request, returns an empty array.

Estoy tratando de crear una unidad de prueba para la situación "si un se produce un error, devuelve nil ".

Me gustaría evitar el uso de OCMock (o subclases de NSManagedObjectContext para reemplazar el método executeFetchRequest: error:) porque supongo que hay una manera fácil de garantizar la falla de este método. Hasta ahora mi prueba de la unidad dice ...

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

¿Hay una manera simple de activar una solicitud de recuperación devolviendo nil?

Respuesta

4

Tuve el mismo enigma. Me gusta mantener la cobertura de la prueba unitaria al 100% siempre que sea posible. No hay una manera fácil de generar una condición de error orgánico. De hecho, no estoy seguro de que la implementación actual de los 4 tipos de tienda que vienen con Core Data alguna vez desencadene un error en respuesta a executeFetchRequest: error. Pero como podría suceder en el futuro, esto es lo que hice:

Tengo un archivo de caso de prueba de unidad que está dedicado a validar cómo mis clases manejan los errores poblados por executeFetchRequest: error. Defino una subclase de NSIncrementalStore que siempre produce un error durante las solicitudes en el archivo de implementación. [NSManagedObjectContext executeFetchRequest:error] es procesado por [NSPersistentStoreCoordinator executeRequest:withContext:error:] que procesa [NSPersistentStore executeRequest:withContext:error:] en todas las tiendas. Puede observar que la palabra "buscar" se cae cuando se mueve al coordinador - las solicitudes de guardado y recuperación se manejan con el mismo métodoexecuteRequest:withContext:error:. De modo que obtengo cobertura para las pruebas contra errores de guardado y solicitudes de búsqueda definiendo un NSPersistentStore que siempre responderá a las tareas de guardado y recuperación con errores.

#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 

Ahora usted puede construir la pila de datos básicos mediante el ErrorProneStore y ser garantizada de Explorar peticiones regresarán nula y poblar el parámetro de error.

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

¡Muy listo! Tengo curiosidad de por qué no subclasificó 'NSManagedObjectContext' y anuló' executeFetchRequest: error: '. Esa ha sido la única solución que he encontrado porque tampoco he encontrado la manera de atraer orgánicamente el error. Subclases más anulación me dejó con un enfoque ligeramente más claro (aunque más limitado). – edelaney05

+2

No subclasé el contexto directamente porque nada en Core Data es tan fácil. [NSManagedObjectContext executeFetchRequest: error] es procesado por [NSPersistentStoreCoordinator executeRequest: withContext: error:] que procesa [NSPersistentStore executeRequest: withContext: error:] en todas las tiendas actuales. Puede observar que la palabra "fetch" cae cuando se mueve al coordinador - las solicitudes de guardar y recuperar se manejan con el mismo método executeRequest: withContext: error :. Así que obtengo cobertura para probar contra guardar errores y buscar solicitudes definiendo ErrorProneStore. –

+0

¡Gracias por la información! – edelaney05

0

En mi opinión, es mucho más fácil de usar 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; 
} 
Cuestiones relacionadas