运行第二次单元测试时,Core Data实体名称为nil

Adr*_*ian 8 core-data ios swift

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

我也得到这个错误:

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
Run Code Online (Sandbox Code Playgroud)

所以我的猜测是我没有做正确的事情 tearDown().

override func setUp() {
    super.setUp()

    coreDataStack = CoreDataStack(storeType: .inMemory)
    context = coreDataStack.context
}

override func tearDown() {
    coreDataStack.reset()
    context = nil
    super.tearDown()
}
Run Code Online (Sandbox Code Playgroud)

这是我的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)
    }
}
Run Code Online (Sandbox Code Playgroud)

并定义为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)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我过去使用这段代码进行单元测试并且它有效,区别在于我NSManagedObject在编辑器中设置类时过去使用了以下配置:

Module - Global namespace
Codegen - Class Definition
Run Code Online (Sandbox Code Playgroud)

现在我使用:

Module - Current Product Module
Codegen - Manual/None
Run Code Online (Sandbox Code Playgroud)

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

那么有谁知道为什么行为现在不同了?

edit - 我的NSManagedObject扩展帮助程序(在尝试检索实体名称时,错误发生在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
    }
}
Run Code Online (Sandbox Code Playgroud)

小智 1

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

尝试用以下替换重置功能:

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)
    }
}
Run Code Online (Sandbox Code Playgroud)

看看您是否仍然遇到问题。