ios - NSPersistentContainer 将加载到应用程序中,不会加载到测试目标中
问题描述
这个问题首先出现在我的应用程序项目中,但让我感到困惑的是,我试图通过切换到遇到相同问题的 Swift 包来简化事情。
在我的项目中,我有一个名为“Model.xcdatamodeld”的数据模型文件(尽管无论名称如何,都会出现同样的问题)。当我在正在运行的应用程序中调用以下 init 方法时,一切运行正常:
init(title: String, then completion: @escaping ()->()) {
self.container = NSPersistentContainer(name: title)
container.loadPersistentStores { description, error in
// don't worry about retaining self, this object lives the whole life of the app
print(description)
if let error = error {
print("Error loading persistent store named \(title): \(error.localizedDescription)")
return
}
completion()
}
}
不打印错误,调用完成块,并且我可以在应用程序的剩余生命周期内访问持久容器的 viewContext。
但是当我在我的测试目标中运行相同的代码时,我会得到非常不同的行为。永远不会输入闭包,当我尝试访问容器的 viewContext 时,它为零。
我已经将测试简化为更简单的东西:
func testLoadingMomD() {
let expectation = XCTestExpectation(description: "core data model is set up")
let container = NSPersistentContainer(name: "Model")
container.loadPersistentStores { description, error in
if let error = error {
print(error.localizedDescription)
}
print(description)
expectation.fulfill()
}
wait(for: [expectation], timeout: 10.0)
}
当我运行这个测试时,我在控制台中得到以下输出:
Test Case '-[GoldfishCoreDataTests.GoldfishCoreDataTests testLoadingMomD]' started.
2020-12-03 22:47:07.695319-0500 xctest[2548:72372] [error] error: Failed to load model named Model
CoreData: error: Failed to load model named Model
/Users/joseph/Documents/QuickScheduling/GoldfishCoreData/GoldfishCoreData/Tests/GoldfishCoreDataTests/GoldfishCoreDataTests.swift:23: error: -[GoldfishCoreDataTests.GoldfishCoreDataTests testLoadingMomD] : Asynchronous wait failed: Exceeded timeout of 10 seconds, with unfulfilled expectations: "core data model is set up".
Test Case '-[GoldfishCoreDataTests.GoldfishCoreDataTests testLoadingMomD]' failed (10.021 seconds).
Test Suite 'GoldfishCoreDataTests' failed at 2020-12-03 22:47:17.714.
Executed 1 test, with 1 failure (0 unexpected) in 10.021 (10.021) seconds
Test Suite 'GoldfishCoreDataTests.xctest' failed at 2020-12-03 22:47:17.715.
Executed 1 test, with 1 failure (0 unexpected) in 10.021 (10.022) seconds
Test Suite 'All tests' failed at 2020-12-03 22:47:17.715.
Executed 1 test, with 1 failure (0 unexpected) in 10.021 (10.022) seconds
Program ended with exit code: 1
如果我在闭包内的任何地方放置一个断点,它就永远不会触发。
当然,我已经验证了 Model.xcdatamodeld 文件在适当的目标中,我什至删除了 Model.xcdatamodeld 并重新创建它而没有任何更改。正如我所说,这发生在我的应用程序项目和一个单独的 Swift 包中,它只包含这个测试代码和 Model.xcdatamodeld 文件。
为了更好地衡量,我在这个项目中有一个 iOS 和一个 macOS 目标,无论我测试哪个目标,我都会得到相同的行为。
在 XCTest 目标中使用 NSPersistentContainer 是不可能的吗?
解决方案
所以简短的回答是 NSPersistentContainer 只在主包中查找其模型文件,除非另有说明。尝试在不是应用程序目标的目标(如测试目标)中使用它,它不会找到模型文件。您必须明确告诉它自己使用哪个模型文件。因此,您必须使用 Bundle 来查找类型为“momd”的资源。
这是我想出的:
enum LoadingError: Error {
case doesNotExist(String)
case corruptObjectModel(URL)
}
init?(title: String, then completion: @escaping (Error?)->()) {
guard let modelURL = Bundle(for: type(of: self)).url(forResource: title, withExtension: "momd") else {
completion(LoadingError.doesNotExist(title))
return nil
}
guard let managedObjectModel = NSManagedObjectModel(contentsOf: modelURL) else {
completion(LoadingError.corruptObjectModel(modelURL))
return nil
}
self.container = NSPersistentContainer(name: title, managedObjectModel: managedObjectModel)
container.loadPersistentStores { description, error in
// don't worry about retaining self, this object lives the whole life of the app
if let error = error {
print("Error loading persistent store named \(title): \(error.localizedDescription)")
DispatchQueue.main.async {
completion(error)
}
return
}
completion(nil)
}
}
顺便说一句,显然您可以通过继承 NSPersistenContainer 来避免这种情况(请参阅https://asciiwwdc.com/2018/sessions/224?q=nspersistentcontainer)。由于其他原因,这不是我的首选选项,但它可能对其他人有用。
推荐阅读
- java - SAXParseException 问题(如何从 xml 文件中去除任何 BOM 字符)
- python - Selenium 获得下一个兄弟姐妹
- checkbox - 检测组件复选框的变化(ng prime)
- python - 读取文件时 Pandas 均值函数中显示意外值
- c# - 为什么使用 DataDirectory 不起作用但使用完整路径起作用?
- r - xlim geom_histogram 错误:美学必须是长度 1 或与数据相同
- postgresql - 当函数不返回任何内容时,postgres 选择不返回任何记录
- reactjs - 使用 require() 导入 React 组件和图像
- import - Rascal:包含导入的符号
- sas - 扫描功能改变一个短语