Имя объекта Core Data равно nil при выполнении второго модульного теста - PullRequest
0 голосов
/ 08 декабря 2018

Я пытаюсь добавить некоторые модульные тесты для своего кода Core Data.Но у меня всегда есть эта проблема, первый тест всегда выполняется правильно, но второй сбой, потому что имя объекта - ноль.

Я также получаю эту ошибку:

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 class:

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 - мой помощник расширения 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
    }
}

1 Ответ

0 голосов
/ 16 декабря 2018

Вы должны попытаться удалить все найденные экземпляры 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)
    }
}

и посмотрите, сохраняется ли проблема.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...