Я пытаюсь добавить некоторые модульные тесты для своего кода 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
}
}