gpt4 book ai didi

ios - iOS10 的 NSPersistentContainer 和单元测试

转载 作者:搜寻专家 更新时间:2023-10-30 23:05:09 27 4
gpt4 key购买 nike

我的单元测试核心数据设置有问题。

我在我的 AppDelegate 中使用默认/新的核心数据堆栈设置

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
}()
}

为了测试,我有一个自定义函数来创建托管上下文

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
}

我有一个扩展来查找给定谓词的第一个项目。

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
}
}

问题来了。

此测试通过:

func testExample() {
let context = setupInMemoryManagedObjectContext()
let entity = try! Entity.first(with: nil, in: context)
XCTAssertEqual(entity, nil)
}

但是如果在 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
}

然后我得到以下错误

failed: caught "NSInvalidArgumentException", "executeFetchRequest:error: is not a valid NSFetchRequest."

错误特别来自 _first() 中的这一行

let fetchRequest = self.fetchRequest() // fetchRequest  is <uninitialized> in that case

但是如果我修改测试以首先创建一个实体,测试将再次正常运行(当然 XCTAssertEqual 是不同的......):

func testExample() {
let context = setupInMemoryManagedObjectContext()
let firstEntity = Entity(context: context)
let entity = try! Entity.first(with: nil, in: context)
XCTAssertEqual(entity, firstEntity)
}

因此出于某种原因,创建一个新实体(不保存上下文)似乎可以使事情恢复原状。

我想我的测试堆栈设置搞砸了,但我还没弄清楚原因。您是否了解正在发生的事情以及正确的设置方法是什么?

我使用的是 Xcode 8.3、Swift 3.1,部署目标是 iOS 10.3。

最佳答案

看起来这是单元测试目标中的核心数据问题(也可能是在使用泛型时)。我在工作中也遇到过,这是我们的解决方案:

func fetchObjects<Entity: NSManagedObject>(type: Entity.Type,
predicate: NSPredicate? = nil,
sortDescriptors: [NSSortDescriptor]? = nil,
fetchLimit: Int? = nil) throws -> [Entity] {

/*
NOTE: This fetch request is constructed this way, because there is a compiler error
when using type.fetchRequest() or Entity.fetchRequest() only in the test target, which
makes the fetchRequest initialize to nil and crashes the fetch at runtime.
*/
let name = String(describing: type)
let fetchRequest: NSFetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: name)

关于ios - iOS10 的 NSPersistentContainer 和单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43231873/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com