测试与非测试中的Swift和CoreData Casting问题

时间:2014-07-08 16:21:18

标签: ios core-data swift

我在Xcode 6上使用Swift和CoreData

我已阅读发行说明并看到此issue有关确保使用模块名称(应用名称)标记核心数据模型,以便您可以投射NSManagedObjectSwift dynamic cast failed运行时的模型类型。

当我这样做时,我可以让应用程序正常运行(好!)。但是,我的问题是,当我尝试测试相同的代码时,每当转换发生myAppname.myEntity错误(错误:()时,测试将始终崩溃。这使得难以测试我的申请。

在为测试与运行构建应用程序时,我们使用的模块名称是否有任何影响?

提前感谢任何指示...

跟进:

这不理想: 如上所述,为了让Swift使用Core Data模型,您需要使用应用程序的名称来装饰类名。这适用于构建应用程序,但测试在不同的应用程序名称下运行!这意味着您需要进入数据建模器并将该类名从myAppnameTests.myEntity更改为{{1}},然后才能在测试使用或调用时按名称使用这些实体。

3 个答案:

答案 0 :(得分:4)

您完全正确,问题在于,当您运行应用程序时,它正在寻找myAppname.myEntity,而当您以Test身份运行时,它看起来像myAppnameTests.myEntity。我此时使用的解决方案(Xcode 6.1)是不填充CoreData UI中的Class字段,而是在代码中填写。

此代码将检测您是否作为App vs Tests运行,并使用正确的模块名称并更新managedObjectClassName

lazy var managedObjectModel: NSManagedObjectModel = {
    // The managed object model for the application. This property is not optional...
    let modelURL = NSBundle.mainBundle().URLForResource("Streak", withExtension: "momd")!
    let managedObjectModel = NSManagedObjectModel(contentsOfURL: modelURL)!

    // Check if we are running as test or not
    let environment = NSProcessInfo.processInfo().environment as [String : AnyObject]
    let isTest = (environment["XCInjectBundle"] as? String)?.pathExtension == "xctest"

    // Create the module name
    let moduleName = (isTest) ? "StreakTests" : "Streak"

    // Create a new managed object model with updated entity class names
    var newEntities = [] as [NSEntityDescription]
    for (_, entity) in enumerate(managedObjectModel.entities) {
        let newEntity = entity.copy() as NSEntityDescription
        newEntity.managedObjectClassName = "\(moduleName).\(entity.name)"
        newEntities.append(newEntity)
    }
    let newManagedObjectModel = NSManagedObjectModel()
    newManagedObjectModel.entities = newEntities

    return newManagedObjectModel
}()

答案 1 :(得分:1)

您需要在Entity.swift文件中添加一行,使其成为像这样的Objective-C类:

@objc(YourEntity)
class YourEntity: NSManagedObject {
    ...
}

如果您的项目不包含任何Objective-c代码,我认为这是一个错误。但是,您需要添加该行,直到此修复。

我是从这里学到的。

Youtube video at 11:45

答案 2 :(得分:1)

这是一个实际适用于我的更新答案。使用XCode 9.2

Ok, I figured it out! It's not exactly intuitive though. First, I had to comment out the @objc(EntityName) line in the NSManagedObject subclasses. Then I went back to the default Module defined in the xcdatamodeld (Current Project Module). Then I had to ensure that only my test classes (and NONE of the NSManagedObject subclasses or any other source files) were compiled as part of my test project (this was critical) and @testable import AppName in my test project class files. Now it never trys to use these classes in the AppNameTests module, only AppName and the test projects can only call public or internal code...therefore all is right in the universe, yay!