代码之家  ›  专栏  ›  技术社区  ›  Adrian

运行第二个单元测试时,核心数据实体名称为nil

  •  8
  • Adrian  · 技术社区  · 7 年前

    我正在尝试为我的核心数据代码添加一些单元测试。但是我总是有这个问题,第一个测试总是正确运行,但是第二个测试崩溃了,因为实体名是nil。

    Multiple NSEntityDescriptions claim the NSManagedObject subclass 'Gym.Exercise' so +entity is unable to disambiguate.
    
    Failed to find a unique match for an NSEntityDescription to a managed object subclass
    

    所以我猜我做的事情不对 tearDown().

    override func setUp() {
        super.setUp()
    
        coreDataStack = CoreDataStack(storeType: .inMemory)
        context = coreDataStack.context
    }
    
    override func tearDown() {
        coreDataStack.reset()
        context = nil
        super.tearDown()
    }
    

    这是我的 CoreDataStack 班级:

    final class CoreDataStack {
        var storeType: StoreType!
        public init(storeType: StoreType) {
            self.storeType = storeType
        }
    
        lazy var persistentContainer: NSPersistentContainer = {
            let container = NSPersistentContainer(name: "Gym")
            container.loadPersistentStores { description, error in
                if let error = error {
                    fatalError("Unresolved error \(error), \(error.localizedDescription)")
                } else {
                    description.type = self.storeType.type
    
                }
            }
    
            return container
        }()
    
        public var context: NSManagedObjectContext {
            return persistentContainer.viewContext
        }
    
        public func reset() {
            guard let store = persistentContainer.persistentStoreCoordinator.persistentStores.first else { fatalError("No store found")}
            guard let url = store.url else { fatalError("No store URL found")}
    
            try! FileManager.default.removeItem(at: url)
            NSPersistentStoreCoordinator.destroyStoreAtURL(url: url)
        }
    }
    

    destroyStoreAtURL :

    extension NSPersistentStoreCoordinator {
        public static func destroyStoreAtURL(url: URL) {
            do {
                let psc = self.init(managedObjectModel: NSManagedObjectModel())
                try psc.destroyPersistentStore(at: url, ofType: NSSQLiteStoreType, options: nil)
            } catch let e {
                print("failed to destroy persistent store at \(url)", e)
            }
        }
    }
    

    NSManagedObject 编辑器中的类我使用了以下配置:

    Module - Global namespace
    Codegen - Class Definition
    

    Module - Current Product Module
    Codegen - Manual/None
    

    因为我想手动添加我的类。

    有人知道为什么现在的行为不同了吗?

    edit-my NSManagedObject extension helper(尝试检索实体名时,fetch()方法的第一行中发生错误):

    extension Managed where Self: NSManagedObject {
    
        public static var entityName: String {
            return entity().name!
        }
    
        public static func fetch(in context: NSManagedObjectContext, configurationBlock: (NSFetchRequest<Self>) -> () = { _ in }) -> [Self] {
            let request = NSFetchRequest<Self>(entityName: Self.entityName)
            configurationBlock(request)
            return try! context.fetch(request)
        }
    
        public static func count(in context: NSManagedObjectContext, configure: (NSFetchRequest<Self>) -> () = { _ in }) -> Int {
            let request = NSFetchRequest<Self>(entityName: entityName)
            configure(request)
            return try! context.count(for: request)
        }
    
        public static func findOrFetch(in context: NSManagedObjectContext, matching predicate: NSPredicate) -> Self? {
            guard let object = materializeObject(in: context, matching: predicate) else {
            return fetch(in: context) { request in
                    request.predicate = predicate
                    request.returnsObjectsAsFaults = false
                    request.fetchLimit = 1
                }.first
            }
    
            return object
        }
    
        public static func materializeObject(in context: NSManagedObjectContext, matching predicate: NSPredicate) -> Self? {
            for object in context.registeredObjects where !object.isFault {
               guard let result = object as? Self, predicate.evaluate(with: result) else {
                   continue
               }
    
               return result
            }
    
            return nil
        }
    
        public static func findOrCreate(in context: NSManagedObjectContext, matching predicate: NSPredicate, configure: (Self) -> ()) -> Self {
            guard let object = findOrFetch(in: context, matching: predicate) else {
               let newObject: Self = context.insertObject()
               configure(newObject)
               return newObject
            }
    
            return object
        }
    }
    
    1 回复  |  直到 7 年前
        1
  •  1
  •   Bhaumik Desai    7 年前

    您应该尝试删除找到的所有persistentStore实例,而不是删除第一个实例。

    尝试将重置功能替换为以下内容:

    public func reset() {
        let stores = persistentContainer.persistentStoreCoordinator.persistentStores
        guard !stores.isEmpty else {
            fatalError("No store found")
        }
        stores.forEach { store in
            guard let url = store.url else { fatalError("No store URL found")}
    
            try! FileManager.default.removeItem(at: url)
            NSPersistentStoreCoordinator.destroyStoreAtURL(url: url)
        }
    }