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?
What is Migration Testing? Migration Testing is a verification process of migration of the legacy system to the new system with minimal disruption/downtime, with data integrity and no loss of data, while ensuring that all the specified functional and non-functional aspects of the application are met post-migration.
To create new unit case in iOS, go to File -> New -> File, and then select Unit Test Case Class. Doing so creates a template just like the one you got with your project. In our case, we want to name the file to correspond with the new Pokemon-related data structures we have introduced.
Data Migration User Acceptance Testing User acceptance testing provides an opportunity for the user community to interact with legacy data in the destination system prior to production release, and most often, this is the first such opportunity for the users.
Swift 3
Replace variables modelName and modelNameVersionFormatString for your models file names
import XCTest
import CoreData
class RCCoreDataMigrationTests: XCTestCase {
private let storeType = NSSQLiteStoreType
private let modelName = "Model"
private let modelNameVersionFormatString = "Model-%@"
private func storeURL(_ version: String) -> URL? {
let storeURL = URL(fileURLWithPath: "\(NSTemporaryDirectory())\(version).sqlite" )
return storeURL
}
private func createObjectModel(_ version: String) -> NSManagedObjectModel? {
let bundle = Bundle.main
let managedObjectModelURL = bundle.url(forResource: modelName, withExtension: "momd")
let managedObjectModelURLBundle = Bundle(url: managedObjectModelURL!)
let modelVersionName = String(format: modelNameVersionFormatString, version)
let managedObjectModelVersionURL = managedObjectModelURLBundle!.url(forResource: modelVersionName, withExtension: "mom")
return NSManagedObjectModel(contentsOf: managedObjectModelVersionURL!)
}
private func createStore(_ version: String) -> NSPersistentStoreCoordinator {
let model = createObjectModel(version)
let storeCoordinator = NSPersistentStoreCoordinator(managedObjectModel: model!)
try! storeCoordinator.addPersistentStore(ofType: storeType,
configurationName: nil,
at: storeURL(version),
options: nil)
return storeCoordinator
}
private func migrateStore(fromVersionMOM: String, toVersionMOM: String) {
let store = createStore(fromVersionMOM)
let nextVersionObjectModel = createObjectModel(toVersionMOM)!
let mappingModel = NSMappingModel(from: [Bundle.main], forSourceModel: store.managedObjectModel, destinationModel: nextVersionObjectModel)!
let migrationManager = NSMigrationManager(sourceModel: store.managedObjectModel, destinationModel: nextVersionObjectModel)
do {
try migrationManager.migrateStore(from: store.persistentStores.first!.url!,
sourceType: storeType,
options: nil,
with: mappingModel,
toDestinationURL: storeURL(toVersionMOM)!,
destinationType: NSSQLiteStoreType,
destinationOptions: nil)
} catch {
print("Error: \(error)")
XCTAssertNil(error)
}
try! FileManager.default.removeItem(at: storeURL(toVersionMOM)!)
try! FileManager.default.removeItem(at: storeURL(fromVersionMOM)!)
}
func testMigratingStores() {
migrateStore(fromVersionMOM: "1486", toVersionMOM: "1487")
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With