Nyc*_*cen 5 core-data ios swift ios10
我的单元测试核心数据设置存在问题.
我在AppDelegate中使用默认/新的Core Data堆栈设置
class AppDelegate: UIResponder, UIApplicationDelegate {
lazy var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "GenericFirstFinder")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
}
Run Code Online (Sandbox Code Playgroud)
为了测试,我有一个自定义函数来创建托管上下文
func setupInMemoryManagedObjectContext() -> NSManagedObjectContext {
let container = NSPersistentContainer(name: "GenericFirstFinder")
let description = NSPersistentStoreDescription()
description.type = NSInMemoryStoreType
container.persistentStoreDescriptions = [description]
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container.viewContext
}
Run Code Online (Sandbox Code Playgroud)
我有一个扩展来查找给出谓词的第一个项目.
extension NSManagedObject {
class func first(with predicate: NSPredicate?, in context: NSManagedObjectContext) throws -> Self? {
return try _first(with: predicate, in: context)
}
fileprivate class func _first<T>(with predicate: NSPredicate?, in context: NSManagedObjectContext) throws -> T? where T: NSFetchRequestResult, T: NSManagedObject {
let fetchRequest = self.fetchRequest()
fetchRequest.fetchLimit = 1
fetchRequest.predicate = predicate
let results = try context.fetch(fetchRequest)
return results.first as? T
}
}
Run Code Online (Sandbox Code Playgroud)
这是问题所在.
该测试通过:
func testExample() {
let context = setupInMemoryManagedObjectContext()
let entity = try! Entity.first(with: nil, in: context)
XCTAssertEqual(entity, nil)
}
Run Code Online (Sandbox Code Playgroud)
但是如果在didFinishLaunchingWithOptions中触发了persistentContainer加载
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
let context = persistentContainer.viewContext // end of laziness
return true
}
Run Code Online (Sandbox Code Playgroud)
然后我收到以下错误
失败:捕获"NSInvalidArgumentException","executeFetchRequest:error:不是有效的NSFetchRequest".
该错误来自_first()中的这一行
let fetchRequest = self.fetchRequest() // fetchRequest is <uninitialized> in that case
Run Code Online (Sandbox Code Playgroud)
但是如果我先修改测试来创建一个实体,那么测试再次运行正常(XCTAssertEqual当然是不同的......):
func testExample() {
let context = setupInMemoryManagedObjectContext()
let firstEntity = Entity(context: context)
let entity = try! Entity.first(with: nil, in: context)
XCTAssertEqual(entity, firstEntity)
}
Run Code Online (Sandbox Code Playgroud)
因此,出于某种原因,创建一个新实体(不保存上下文)似乎会使事情恢复正常.
我想我的测试堆栈设置搞砸了,但我还没弄清楚原因.你了解正在发生的事情以及设置的正确方法是什么?
我正在使用Xcode 8.3,Swift 3.1,部署目标是iOS 10.3.
我不熟悉类函数fetchRequest,并且在查找此问题之前不知道它的存在。
我查阅了 一些 参考资料,但不得不承认我仍然不明白发生了什么。
最近,我一直在使用 Xcode 创建的自动生成的类,该类为每个实体包含一个fetchRequest如下所示的方法:
@nonobjc public class func fetchRequest() -> NSFetchRequest<User> {
return NSFetchRequest<Entity>(entityName: "Entity")
}
Run Code Online (Sandbox Code Playgroud)
使用它作为格式,我将_first函数中的一行更改为:
fileprivate class func _first<T>(with predicate: NSPredicate?, in context: NSManagedObjectContext) throws -> T? where T: NSFetchRequestResult, T: NSManagedObject {
// let fetchRequest = self.fetchRequest()
// (note that this wouldn't work if the class name and entity name were not the same)
let fetchRequest = NSFetchRequest<T>(entityName: T.entity().managedObjectClassName)
fetchRequest.fetchLimit = 1
fetchRequest.predicate = predicate
let results = try context.fetch(fetchRequest)
return results.first
}
Run Code Online (Sandbox Code Playgroud)
对我来说,这可以防止错误 - 我发布此内容是为了看看它是否对您有帮助,但我将不得不进行更多调查以了解其原理。
| 归档时间: |
|
| 查看次数: |
559 次 |
| 最近记录: |