2012-08-14 112 views
14

我正在使用自定義實體遷移策略爲遷移創建映射模型,並且我真的想爲此遷移構建一些單元測試。當我運行應用程序時,遷移似乎正常工作,但是當我通過單元測試運行遷移時,我的NSEntityMigrationPolicy子類方法根本不會被調用。我如何測試核心數據遷移?

我正在使用Xcode的內置OCUnit框架。

我的測試代碼:

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

我的映射模型指定用於定義-createRelationshipsForDestinationInstance:entityMapping:manager:error:方法定製NSEntityMigrationPolicy,但我的政策是永遠不會從單元測試調用。當我運行遷移時,模型被修改爲新版本 - 預期的屬性顯示在正確的位置。

任何想法如何讓我的遷移政策在單元測試中工作?

回答

4

問題被證明是在線路

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

如果我將其改變爲

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

然後測試功能正常。

2

斯威夫特3

替換變量MODELNAMEmodelNameVersionFormatString爲您的模型文件名

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