56 votes

Comment tester un peu mes modèles maintenant que j'utilise Core Data?

J'ai développé une application iphone à l'aide d'un modèle de domaine, et mis la persistance aspect de l'application jusqu'à maintenant. Base de Données ressemble à une très bonne solution puisque j'ai déjà un modèle bien défini, mais je suis en cours d'exécution un hic, mes tests unitaires.

Ici est simple exemple de ce que j'ai maintenant:

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

Comment puis-je faire de ce travail une fois que mon Patient objet s'étend à partir de NSManagedObject et utilise @dynamique pour les propriétés firstName et lastName?

Quelqu'un d'autre a rencontré ce type de ce avec la Base de Données? Merci.

85voto

Barry Wark Points 73462

Vous avez besoin de construire une Base de Données de la pile, soit à l'intérieur de chaque méthode ou en -setUp , puis de les démonter. À l'aide d'un NSInMemoryPersistentStore garder les choses rapidement et en mémoire pour vos tests unitaires. Ajouter un @property (nonatomic,retain) NSManagedObjectContext *moc à votre cas de test sous-classe. Alors:

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

Votre méthode de test ressemble alors à:

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

en supposant que votre entité est nommé en Person. Il y avait une fuite de mémoire dans votre version de la méthode, par la façon dont le patient doit être -release'd dans le non-Base de Données version (insertNewObjectForEntityForName:managedObjectContext: renvoie un autoreleased exemple).

22voto

mikebz Points 554

J'ai utilisé la réponse ci-dessus de Barry Wark, mais j'ai dû faire quelques modifications pour que cela fonctionne avec les projets actuels XCode5, iOS7.

La propriété est restée la même:

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

La configuration devait en réalité être modifiée en premier lieu pour ne pas publier et en second lieu pour fournir un modèle d'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;
}
 

Voici l'exemple de cas de 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");
}
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X