Swift / OSX - 如何在不运行应用程序的情况下为单元测试提供Core Data访问并运行测试

时间:2018-02-25 20:05:02

标签: swift macos unit-testing core-data

我在我的小而简单的应用程序中使用Core Data。它工作正常。在开始开发应用程序并使其更复杂之前,我想设置一些单元测试。有一些箍你需要跳过才能实现这一点,但我在SE上找到了numerous useful answers让我通过这些箍。基本思想是您必须手动创建对象模型。很容易;我从上面链接的一个答案中修改了这个代码,问题就解决了。

let managedObjectModel = NSManagedObjectModel.mergedModel(from: [Bundle.main])!
let persistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: managedObjectModel)
try! persistentStoreCoordinator.addPersistentStore(ofType: NSInMemoryStoreType, configurationName: nil, at: nil, options: nil)

let managedObjectContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
managedObjectContext.persistentStoreCoordinator = persistentStoreCoordinator

NSEntityDescription.entity(forEntityName: "VAgentEditor", in: managedObjectContext)!

大。但我也希望在不运行应用程序的情况下运行我的测试,只是为了测试我的低级逻辑。更多的箍要跳过。很多有用的answers也解决了这个问题。

当我尝试在没有应用程序窗口的情况下访问核心数据时,会出现问题。天真地将这两个问题的解决方案结合起来,我从调用NSEntityDescription.entity()开始就没有了。我已经用我能想到的各种方式调整了上面的代码,但无济于事。如果我能够通过调用entity()获得足够的nil,那么我最终会收到VAgentEditor无法找到的消息,或者当我尝试将上下文保存到磁盘时,我得到一个看起来像中途工作的文件 - 其中有很多东西,但是当我只尝试上述两种工作方案中的一种时,我没有VAgentEditor

当我尝试将单元测试指向主应用程序的捆绑包时,我收到有关未找到捆绑包的各种投诉,或者单元测试无法同时使用其自己的捆绑包和应用程序包,还有一百个其他的抱怨,在我这几天黑客攻击之后我都不记得了。

有没有办法让我的单元测试使用CoreData,访问正确的bundle来获取我在Interface Builder中定义的类,并运行测试而不运行主应用程序?

1 个答案:

答案 0 :(得分:1)

如果使用CoreStore进行数据库处理,一切都会更容易。使用以下代码设置数据库:

<parent container>
  <div float right></div>
  <macy container>
<? SELECT * FROM table ORDER BY id DESC ?>
<? while ... { ?>
    <post>
<? } ?>
  </macy container>
</parent container>

假设您有以下数据库对象:

let dataStack: DataStack = {
    let dataStack = DataStack(xcodeModelName: "ModelName")
    do {
        try dataStack.addStorageAndWait()
    } catch let error {
        XCTFail("Cannot set up database storage: \(error)")
    }
    return dataStack
}()

您可以像这样运行单元测试:

class User: NSManagedObject {

    @NSManaged var name: String

    func rename(name: String, transaction: BaseDataTransaction?) {
        guard let user = transaction.edit(self) else {
            return
        }
        user.name = name
    }

}

这只是一个开始。你可以简化和改进整个过程,但我希望你能理解。