Search code examples
iosunit-testingcore-dataocunitcore-data-migration

How can I unit test a Core Data migration?


I'm building a mapping model for my migration with a custom entity migration policy, and I'd really like to build some unit tests for this migration. The migration seems to work correctly when I run the app, but my NSEntityMigrationPolicy subclass methods are not called at all when I run the migration via a unit test.

I'm using Xcode's built-in OCUnit framework.

My test code:

- (void)test1to2Migration_appIdentifierMoved {
  [self createVersion1Store];

  // TODO Perform migration
  NSManagedObjectModel *version1Model = [self version1Model];
  NSManagedObjectModel *version2Model = [self version2Model];

  NSError *error = nil;
  NSMappingModel *mappingModel = [NSMappingModel
      inferredMappingModelForSourceModel:version1Model
      destinationModel:version2Model error:&error];
  STAssertNotNil(mappingModel, @"Error finding mapping model: %@", error);

  NSMigrationManager *migrationManager =
      [[[NSMigrationManager alloc]
        initWithSourceModel:version1Model
        destinationModel:version2Model]
       autorelease];

  BOOL migrationSucceeded =
      [migrationManager migrateStoreFromURL:self.version1StoreURL
           type:NSSQLiteStoreType
           options:nil
           withMappingModel:mappingModel
           toDestinationURL:self.version2StoreURL
           destinationType:NSSQLiteStoreType
           destinationOptions:nil
           error:&error];
  STAssertTrue(migrationSucceeded, @"Error migrating store: %@", error);

  // TODO Verify appIdentifier is moved from Project to its Tests

  [self deleteTempStores];
}

My mapping model specifies a custom NSEntityMigrationPolicy that defines the -createRelationshipsForDestinationInstance:entityMapping:manager:error: method, but my policy is never called from the unit test. When I run the migration, the model is modified to the new version -- the expected attributes show up in the right places.

Any ideas how I can get my migration policy to work in a unit test?


Solution

  • The problem turned out to be in the line

    NSMappingModel *mappingModel = [NSMappingModel
      inferredMappingModelForSourceModel:version1Model
      destinationModel:version2Model error:&error];
    

    If I change it to

    NSMappingModel *mappingModel = [NSMappingModel
      mappingModelFromBundles:@[[NSBundle bundleForClass:[MyTestClass class]]]
      forSourceModel:version1Model destinationModel:version2Model];
    

    then the test functions correctly.