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

2023-11-26

我有一个 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对象和致命错误:

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

由该行提出:

for list: List in lists {

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

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

Update:

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

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班级有两个目标。事实上,有两个ListSwift 已知的类,每个目标一个:MyAppTarget.List and MyUnitTestTarget.List。 Reetched 结果控制器返回数组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 into MyUnitTestTarget.List在单元测试中,它仍然需要List类要公开。

Update:

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

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 Swift 中对 NSFetchedResultsController 进行单元测试 的相关文章

随机推荐

  • 如何使用 OKHTTP 取消请求

    我需要能够MANAGER一些请求与OKHTTP 使用Google Places AutoComplete通过输入地址来接收一些预测 这问题是每次我插入一个CHAR它会提出一个新的请求 但同时我需要取消前一个请求 例如 纽约市 同时有 13
  • 在java中使用10个线程打印1到100

    我是多线程新手 我有一个问题是在 Java 中使用 10 个线程在以下约束下打印 1 到 100 Thread t1应该打印 1 11 21 31 91 t2应该打印 2 12 22 32 92 likewise t10应该打印 10 20
  • 如何仅使用脚本创建自制公式

    我想将一些 shell 脚本 支持文件打包成一个自制程序 将这些脚本安装在用户的某个地方 PATH 我将用我自己的水龙头提供配方 阅读通过配方食谱这些示例似乎假设上游库中存在 cmake 或 autotools 系统 如果我的项目仅包含几个
  • htaccess 重定向 + 隐藏 url 中的子文件夹

    我环顾四周并尝试了一些有效的规则和条件 虽然有些不起作用 或者条件会捕获太多导致其他域也重定向 这对我有用 Redirect also catches www RewriteCond HTTP HOST www domain com Rew
  • TBN 矩阵中的法向量、切向量和双切向量总是垂直的吗?

    这与另一个问题中描述的问题有关 那里有图片 Opengl 着色器问题 奇怪的光反射伪像 我有一个 obj 导入器 它创建数据结构并计算切线和双切线 这是我的对象中第一个三角形的数据 我对切线空间的理解是 法线从顶点向外指向 切线垂直 正交
  • Java - 匿名内部类生命周期

    当使用匿名内部类作为 PropertyChangeListener 时 该类会在对象生命周期的哪个点被垃圾回收 包含类 SettingsNode 被回收后 我是否应该显式删除包含类 SettingsNode 的终结器中的 PropertyC
  • forking() 和 CreateProcess()

    forking 和 CreateProcess 带有所有必需的参数 对于 Linux 和 WinXP 来说分别是一样的吗 如果它们不同 那么有人可以解释这两种情况下发生的情况的差异吗 Thanks 他们在不同的系统上做不同的事情 Creat
  • 将列转换为行并保留列名称

    R 有什么方法可以将列转换为行并保留列的名称吗 输入示例 A B 1 1 2 3 3 4 44 5 Output Group Number A 1 A 2 A 3 A 44 B 1 B 3 B 4 B 5 无需使用reshape2 您可以使
  • jQuery - 如何选择除特定复选框之外的所有复选框?

    我有一个 jQuery 选择器 看起来像这样 input checkbox click function event DO STUFF HERE 一切都运行良好 直到我被要求添加另一个与原始复选框无关的复选框 如何为除一个复选框之外的所有复
  • 如何创建不依赖于 C 运行时的 Win32 DLL

    使用 Visual Studio 2008 及其 C C 编译器 如何创建仅依赖于其他 Windows DLL 而不依赖于 Microsoft C 运行时的 Win32 DLL 我想将一些 C 代码放入完全计算的 DLL 中 并且几乎不使用
  • Java常量池的用途是什么?

    我目前正在尝试更深入地研究Java虚拟机的规范 我一直在阅读 JVM 内幕 在线书籍有一个令人困惑的抽象我似乎无法理解 常量池 以下是这本书的摘录 对于它加载的每种类型 Java 虚拟机必须存储一个常量池 常量池是类型使用的一组有序常量 包
  • 为什么 android InputMethodManager.showSoftInput() 返回 false?

    最近在开发应用程序时 我遇到了一个问题 我在谷歌上搜索了很多 但找不到任何解决方案 最后我遇到了这个Android 问题跟踪器 为了解释我的问题 我制作了一个示例应用程序 我的示例应用程序的基本工作 我有一个屏幕 其中有一个 EditTex
  • ubuntu18.04上的pyside2安装问题,anaconda上的python 3.8.3

    安装完anaconda3后 开始安装pyside2 我直接输入pip install pyside2 并成功安装pyside2 5 15 但是当我运行玩具示例时 发生了错误 Traceback most recent call last F
  • 自动将 protobuf 规范编译到 setup.py 中的 python 类中

    我有一个 python 项目 它使用 google protobufs 作为通过网络进行通信的消息格式 使用以下命令可以直接从 proto 文件生成 python 文件protoc程序 我该如何配置我的setup py项目文件 以便它自动调
  • 如何在 Javascript 中循环月份

    我正在尝试生成以月为单位的字符串日期列表 即 2014 年 10 月 2014 年 11 月 2015 年 1 月 使用这里的代码 var resultList var date new Date October 13 2014 var e
  • 将 matplotlib 填充的等高线图保存为 .pdf 或 .eps 时出现别名

    我正在使用 matplotlib pyplot contourf 函数生成一个归档等高线图 函数调用中的参数是 contourf xvec xvec w levels cmap matplotlib cm jet where xvec nu
  • WCF 代理返回数组而不是列表,即使集合类型 == Generic.List

    我有一个 VS 2010 解决方案 其中包含一个 WCF 库项目和另一个使用该 Web 服务的项目 在VS 2012中打开后 进行了升级 代理现在将 List 类型作为数组返回 即使 CollectionMappings 明确设置为 Gen
  • 更改 IdentityServer 4 中的默认端点

    我正在研究 IdentityServer 4 1 0 0 beta5 默认情况下 身份验证的端点是 连接 令牌 如何更改 IdentityServer 中的默认端点 例如 api login Thanks 在启动时设置 Identity S
  • 在 iOS 和 OSX 上使用 unsigned int 和 unsigned long 编译 NSLog,不会出现警告

    On iOS NSUInteger is a unsigned int 在 OSX 上它是unsigned long 我怎样才能做出像这样的打印声明 NSLog Array has d elements array count 在两个平台上
  • 如何在 Swift 中对 NSFetchedResultsController 进行单元测试

    我有一个 Swift 应用程序 它使用NSFetchedResultsController获取List来自持久存储的对象 let fetchedResultsController NSFetchedResultsController var