2009-12-04 18 views
55

Ho sviluppato un'applicazione per iPhone utilizzando un modello di dominio e ho rimandato l'aspetto di persistenza dell'app fino ad ora. Core Data sembra davvero un'ottima soluzione poiché ho già un modello ben definito, ma mi trovo in difficoltà con i miei test unitari esistenti.Come testare unitamente i miei modelli ora che sto usando Core Data?

Ecco semplice esempio di quello che ho adesso:

- (void)test_full_name_returns_correct_string { 
    Patient *patient = [[Patient alloc] init]; 
    patient.firstName = @"charlie"; 
    patient.lastName = @"chaplin"; 
    STAssertTrue([[patient fullName] isEqualToString:@"charlie chaplin"], @"should have matched full name"); 
} 

Come posso fare questo lavoro una volta che il mio oggetto del paziente si estende da NSManagedObject e usa @dynamic per le proprietà firstName e lastName?

Qualcun altro ha eseguito questo tipo di questo con Core Data? Grazie.

risposta

84

È necessario creare uno stack di dati principali, all'interno di ciascun metodo o in -setUp e quindi eliminarlo. L'utilizzo di un NSInMemoryPersistentStore manterrà le cose veloci e in memoria per i test dell'unità. Aggiungi un @property (nonatomic,retain) NSManagedObjectContext *moc alla sottoclasse TestCase. Poi:

- (void)setUp { 
    NSManagedObjectModel *mom = [NSManagedObjectModel mergedModelFromBundles:[NSArray arrayWithObject:bundleContainingXCDataModel]]; 
    NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom]; 
    STAssertTrue([psc addPersistentStoreWithType:NSInMemoryStoreType configuration:nil URL:nil options:nil error:NULL] ? YES : NO, @"Should be able to add in-memory store");  
    self.moc = [[NSManagedObjectContext alloc] init]; 
    self.moc.persistentStoreCoordinator = psc; 

    [mom release]; 
    [psc release]; 

} 

- (void)tearDown { 
    self.moc = nil; 
} 

tuo metodo di prova si presenta quindi come:

- (void)test_full_name_returns_correct_string { 
    Patient *patient = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:self.moc]; 

    patient.firstName = @"charlie"; 
    patient.lastName = @"chaplin"; 
    STAssertTrue([[patient fullName] isEqualToString:@"charlie chaplin"], @"should have matched full name"); 
} 

supponendo che il soggetto è chiamato Person. A proposito, c'è stata una perdita di memoria nella tua versione del metodo; il paziente deve essere -release nella versione non Core Data (insertNewObjectForEntityForName:managedObjectContext: restituisce un'istanza autorizzata).

+0

Grazie per l'aiuto. Andrò questa strada. Riguardo alla perdita di memoria, non mi sono preoccupato di ripulire la memoria nei miei test di unità. Sembra più leggibile per me senza le versioni. C'è un vantaggio nel mantenere le prove fuoriuscite? –

+2

Se i test perdono, è davvero difficile usare la suite di test unitaria per verificare il tuo * altro * codice per perdite. Gli strumenti hanno un analizzatore di perdite che è fondamentalmente inutile se oscurate * reall * perdite con perdite non necessarie (ma intenzionali) delle stesse classi nel codice di test. –

+3

Penso che dopo un po 'scoprirai che il codice di conservazione/rilascio scompare dalla visione cosciente. Raramente me ne accorgo più, a meno che non manchi. –

22

Ho usato la risposta di cui sopra Barry Wark, ma ho dovuto apportare alcune modifiche per farlo funzionare con i progetti attuali XCode5, iOS7.

La proprietà rimasta la stessa:

@interface SIDataTest : XCTestCase 
    @property (nonatomic,retain) NSManagedObjectContext *moc; 
@end 

Il setup doveva aveva effettivamente di cambiare prima di tutto di non rilasciare e in secondo luogo per fornire un modello di URL.

- (void)setUp 
{ 
    [super setUp]; 
    NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"SimpleInvoice" withExtension:@"momd"]; 
    NSManagedObjectModel *mom = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL]; 
    NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom]; 
    XCTAssertTrue([psc addPersistentStoreWithType:NSInMemoryStoreType configuration:nil URL:nil options:nil error:NULL] ? YES : NO, @"Should be able to add in-memory store"); 
    self.moc = [[NSManagedObjectContext alloc] init]; 
    self.moc.persistentStoreCoordinator = psc; 
} 

Qui è il caso ad esempio di test:

- (void)testCreateNew 
{ 
    Invoice *newInvoice = [NSEntityDescription insertNewObjectForEntityForName:@"Invoice" inManagedObjectContext:self.moc]; 
    newInvoice.dueDate = [NSDate date]; 
    NSString* title = [[NSString alloc] initWithFormat:@"Invoice %@", @112]; 
    newInvoice.title = title; 

    // Save the context. 
    NSError *error = nil; 
    if (![self.moc save:&error]) { 
     // Replace this implementation with code to handle the error appropriately. 
     // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. 
     XCTFail(@"Error saving in \"%s\" : %@, %@", __PRETTY_FUNCTION__, error, [error userInfo]); 
    } 
    XCTAssertFalse(self.moc.hasChanges,"All the changes should be saved"); 
} 
Problemi correlati