gpt4 book ai didi

unit-testing - 如何在 Swift 中对 NSFetchedResultsController 进行单元测试

转载 作者:IT王子 更新时间:2023-10-29 05:53:30 29 4
gpt4 key购买 nike

我有一个 Swift 应用程序,它使用 NSFetchedResultsController 从持久存储中获取 List 对象:

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

它按预期工作,我将 List 对象描述打印到控制台。我想为我的应用编写一些单元测试,因此我创建了扩展 XCTestCase 的类。代码编译没有问题,测试运行,但不幸的是我无法在该上下文中获取 List 对象。

我在控制台中得到的只是 List 对象的计数和一个 fatal error :

lists count = 59
fatal error: NSArray element failed to match the Swift Array Element type

上升线:

for list: List in lists {

我很确定我的目标配置正确,因为我可以创建 List 对象并将其插入到托管对象上下文中,而我的应用程序源代码和单元测试源代码不会出现问题。我遇到的唯一问题是从测试单元中获取。我想知道为什么在模拟器中运行应用程序时抓取有效,而在单元测试期间执行时失败。

任何可能出错的想法都将不胜感激。

更新:

为了更具体地说明我的实现方式,这里是我正在使用的完整代码示例:

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

当我从我的应用程序的源代码执行它时,在模拟器中运行该应用程序,控制台输出如下所示:

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";
})

但是,当我从单元测试中执行这段代码时,我得到了这样的输出:

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

我希望它能让您更容易理解问题出在哪里。不知何故,这个声明:

let fetchedLists: [List]? = fetchedResultsController.fetchedObjects as? [List]

当应用程序在模拟器中运行时生成一个 List 对象数组,但当从单元测试执行时它无法生成 nil

最佳答案

问题与目标配置有关。我已经通过一些变通办法解决了这个问题。

以前,为了使 List 实体类在我的单元测试目标中可访问,我已将它添加到此目标中。因此,List 类有两个目标。事实上,Swift 已知有两个 List 类,每个目标一个:MyAppTarget.ListMyUnitTestTarget.List。 Retched 结果 Controller 返回 MyAppTarget.List 对象数组,但在单元测试目标中,List 被假定为 MyUnitTestTarget.List 类。这行代码就是这样:

let fetchedLists: [List]? = fetchedResultsController.fetchedObjects as? [List]

从单元测试目标执行时生成 nil,而不是从主目标执行时生成的正确数组。为了解决这个问题,我将其更改为:

let fetchedLists: [MyAppTarget.List]? = fetchedResultsController.fetchedObjects as? [MyAppTarget.List]

并公开List 类。更改后,它按预期工作。

但是,MyAppTarget.List 不能转换为 MyUnitTestTarget.List 还是让我有点困惑。此外,这意味着我需要公开每个实体 NSManagedObject 子类,以便在单元测试中使用它。到目前为止,我没有找到更好的解决方案。

也许有更好的方法来解决这个问题。我没有看到一个选项告诉 NSFetchedResultsController 它应该在主目标中返回 MyAppTarget.List,在单元测试目标中返回 MyUnitTestTarget.List .对于给定实体,它将始终使用 .xcdatamodeld 文件中的配置。此外,即使有一种方法可以在单元测试中将 MyAppTarget.List 转换为 MyUnitTestTarget.List,它仍然需要 List 类公开。

更新:

我找到了一种在运行时更改 NSFetchedResultsController 返回的实体类的方法。这是一个更清晰和简单的解决方案:https://stackoverflow.com/a/25858758/514181

它允许在单元测试中无缝使用 CoreData 实体,而无需强制转换或公开实体类。

关于unit-testing - 如何在 Swift 中对 NSFetchedResultsController 进行单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25815117/

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