Ich habe einen Swift-App, die NSFetchedResultsController
List
Objekte aus persistenten Speichern zu holen verwendet:Wie Unit-Test NSFetchedResultsController in Swift
let fetchedResultsController: NSFetchedResultsController = ...
var error : NSError?
fetchedResultsController.performFetch(&error)
if let error = error {
NSLog("Error: \(error)")
}
let lists: [List] = fetchedResultsController.fetchedObjects! as [List]
NSLog("lists count = \(lists.count)")
for list: List in lists {
NSLog("List: \(list.description)")
}
und es wie erwartet funktioniert, ich bin immer List
Beschreibungen Objekte in dem ausgedruckten Konsole. Ich möchte einige Komponententests für meine App schreiben, also habe ich Klasse erstellt, die XCTestCase
erweitert. Der Code kompiliert ohne Probleme, Tests laufen, aber leider kann ich die List
Objekte in diesem Zusammenhang nicht abrufen.
Alles, was ich bin in der Konsole immer Anzahl der List
Objekte und ein fataler Fehler:
lists count = 59
fatal error: NSArray element failed to match the Swift Array Element type
durch die Linie rised:
for list: List in lists {
Ich bin mir ziemlich sicher, dass ich Ziele richtig konfiguriert ist, wie ich List
Objekt erstellen und es in den Kontext von verwalteten Objekten problemlos aus dem Quellcode meiner App sowie aus Unit-Testquellcode einfügen kann. Das einzige Problem, das ich erlebe, ist das Abholen von der Testeinheit. Ich frage mich, warum das Abrufen funktioniert, wenn die App im Simulator ausgeführt wird, und fehlschlägt, wenn es während des Komponententests ausgeführt wird.
Alle Ideen, die falsch sein könnten, werden geschätzt.
Update:
Um genauer zu sein, wie meine Implementierung aussieht, ist hier komplette Codebeispiel, mit denen ich spielen:
var error: NSError? = nil
let urls = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
let applicationDocumentsDirectory = urls[urls.count-1] as NSURL
let modelURL = NSBundle.mainBundle().URLForResource("CheckLists", withExtension: "momd")!
let managedObjectModel = NSManagedObjectModel(contentsOfURL: modelURL)
var coordinator: NSPersistentStoreCoordinator? = NSPersistentStoreCoordinator(managedObjectModel: managedObjectModel)
let url = applicationDocumentsDirectory.URLByAppendingPathComponent("CheckLists.sqlite")
if coordinator!.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: nil, error: &error) == nil {
NSLog("Error1: \(error)")
abort()
}
var managedObjectContext = NSManagedObjectContext()
managedObjectContext.persistentStoreCoordinator = coordinator
let fetchRequest = NSFetchRequest()
fetchRequest.entity = NSEntityDescription.entityForName("List", inManagedObjectContext: managedObjectContext)
fetchRequest.sortDescriptors = [ NSSortDescriptor(key: "name", ascending: true) ]
let fetchedResultsController = NSFetchedResultsController(
fetchRequest: fetchRequest,
managedObjectContext: managedObjectContext,
sectionNameKeyPath: nil,
cacheName: "ListFetchedResultsControllerCache"
)
fetchedResultsController.performFetch(&error)
if let error = error {
NSLog("Error2: \(error)")
abort()
}
let fetchedObjects: [AnyObject]? = fetchedResultsController.fetchedObjects
if let fetchedObjects = fetchedObjects {
NSLog("Fetched objects count: \(fetchedObjects.count)")
for fetchedObject in fetchedObjects {
NSLog("Fetched object: \(fetchedObject.description)")
}
}
else {
NSLog("Fetched objects array is nil")
}
let fetchedLists: [List]? = fetchedResultsController.fetchedObjects as? [List]
if let fetchedLists = fetchedLists {
NSLog("Fetched lists count: \(fetchedLists.count)")
for fetchedList in fetchedLists {
NSLog("Fetched list: \(fetchedList.description)")
}
}
else {
NSLog("Fetched lists array is nil")
}
Wenn ich es von meiner App-Quellcode ausführen, Wenn Sie die App im Simulator ausführen, sieht die Konsolenausgabe wie folgt aus:
Fetched objects count: 3
Fetched object: <CheckLists.List: 0x7a6866f0> (entity: List; id: 0x7a686020 <x-coredata://7A87B5BE-C2FA-4150-B9E3-879FDE07F0B9/List/p2> ; data: {
name = "List 1";
})
Fetched object: <CheckLists.List: 0x7a686930> (entity: List; id: 0x7a686030 <x-coredata://7A87B5BE-C2FA-4150-B9E3-879FDE07F0B9/List/p1> ; data: {
name = "List 2";
})
Fetched object: <CheckLists.List: 0x7a686970> (entity: List; id: 0x7a686040 <x-coredata://7A87B5BE-C2FA-4150-B9E3-879FDE07F0B9/List/p3> ; data: {
name = "List 3";
})
Fetched lists count: 3
Fetched list: <CheckLists.List: 0x7a6866f0> (entity: List; id: 0x7a686020 <x-coredata://7A87B5BE-C2FA-4150-B9E3-879FDE07F0B9/List/p2> ; data: {
name = "List 1";
})
Fetched list: <CheckLists.List: 0x7a686930> (entity: List; id: 0x7a686030 <x-coredata://7A87B5BE-C2FA-4150-B9E3-879FDE07F0B9/List/p1> ; data: {
name = "List 2";
})
Fetched list: <CheckLists.List: 0x7a686970> (entity: List; id: 0x7a686040 <x-coredata://7A87B5BE-C2FA-4150-B9E3-879FDE07F0B9/List/p3> ; data: {
name = "List 3";
})
Allerdings, wenn ich diesen Code von einem ausführen Unit-Test, bekomme ich diese Ausgabe:
Fetched objects count: 3
Fetched object: <CheckLists.List: 0x7a07df50> (entity: List; id: 0x7a07d7e0 <x-coredata://7A87B5BE-C2FA-4150-B9E3-879FDE07F0B9/List/p2> ; data: {
name = "List 1";
})
Fetched object: <CheckLists.List: 0x7a07e190> (entity: List; id: 0x7a07d7f0 <x-coredata://7A87B5BE-C2FA-4150-B9E3-879FDE07F0B9/List/p1> ; data: {
name = "List 2";
})
Fetched object: <CheckLists.List: 0x7a07e1d0> (entity: List; id: 0x7a07d800 <x-coredata://7A87B5BE-C2FA-4150-B9E3-879FDE07F0B9/List/p3> ; data: {
name = "List 3";
})
Fetched lists array is nil
Ich hoffe, es macht es leichter zu verstehen, wo das Problem liegt. Irgendwie diese Aussage:
let fetchedLists: [List]? = fetchedResultsController.fetchedObjects as? [List]
produziert eine Reihe von List
Objekten, wenn app im Simulator ausgeführt wird, aber es funktioniert nicht nil
erzeugen, wenn von Unit-Test durchgeführt.
Haben Sie Ihre Objektmodelldatei ('momd') in Ihrem Testpaket enthalten? Und ist die Modelldatei so eingerichtet, dass sie die Unterklasse 'List' für die Listenentität verwendet? – MrAlek
@MrAlek - Ich bin mir nicht sicher, ob meine '.momd' Datei im Testpaket enthalten ist. Ich erstelle ein solches Modell: 'NSManagedObjectModel (NSBundle.mainBundle(). URLForResource (" CheckLists ", mitExtension:" momd ")!)' Und es funktioniert sowohl für das Hauptziel als auch für das Testziel. Könnten Sie genauer sein? – Darrarski
@MrAlek - In meiner '.xcdatamodeld' Datei habe ich die korrekte Klasse für' List' Entität eingerichtet. Ich kann sogar neue Entitäten in meinen Komponententests erstellen und sie in den Kontext einfügen. Es bleibt in der Datenbank bestehen, wenn der Kontext gespeichert wird. – Darrarski