Swift无法在Xcodetesting中testing核心数据?

我正在使用核心数据的iOS项目。 我正在使用swift。 核心数据堆栈设置正确,似乎都很好。 我创build了一个称为TestEntity的实体(NSManagedObject)的类。 这个类看起来像这样:

import UIKit import CoreData class TestEntity: NSManagedObject { @NSManaged var name: NSString @NSManaged var age: NSNumber } 

所以,然后我尝试在代码中插入一个新的TestEntity使用这行代码:

 let te: TestEntity = NSEntityDescription.insertNewObjectForEntityForName("TestEntity", inManagedObjectContext: ctx) as TestEntity 

然后我得到这个错误:

在这里输入图像说明

我已经看到了堆栈溢出的一些答案,说我需要担心模块名称。 那么我查看了这个文档: https : //developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/WritingSwiftClassesWithObjective-CBehavior.html

然后,我进入TestEntity的核心数据实体,并在类字段中inputmyAppName.TestEntity

当我运行应用程序这一行:

 let te: TestEntity = NSEntityDescription.insertNewObjectForEntityForName("TestEntity", inManagedObjectContext: ctx) as TestEntity 

仍然给我同样的错误。

我还能做什么错?

编辑:所以,我能够通过更改TestEntity NSManagedObject类以使应用程序不再崩溃:import UIKit import CoreData

 @objc(TestEntity) class TestEntity: NSManagedObject { @NSManaged var name: NSString @NSManaged var age: NSNumber } 

所以,我添加了@objc(TestEntity)。 这可以在核心数据数据模型检查器中的TestEntity类名之前添加或不添加appName。

这工作,但是,当我运行testing这条线仍然崩溃

 let te: TestEntity = NSEntityDescription.insertNewObjectForEntityForName("TestEntity", inManagedObjectContext: ctx) as TestEntity 

所以我发现这对其他人来说是一个问题: 如何在testing目标中访问Core Data生成的Obj-C类?

我们怎样才能让核心数据在testing中快速工作 。 我没有在应用程序目标中使用桥接标头,并且这一切都很好。 testing目标仍然崩溃。

如何修复testing目标,以便运行核心数据testing?

使用Xcode 7和@testable ,您不再需要更新managedObjectClassName或使用其他黑客。 以下是我在Xcode 7.2中的工作。

  1. 设置您的testing目标主机应用程序,并选中“允许testing主机应用程序API”。

在这里输入图像说明

  1. 确保你的普通class级没有一个目标成员指向testing目标。 只有具有unit testing代码的类才能被设置为testing目标。

在这里输入图像说明

  1. @testable行添加到所有testing类的顶部:
 import XCTest @testable import MyApp class MyAppTests: XCTestCase { } 

如果您仍然遇到问题,可以尝试以下其他提示: https : //forums.developer.apple.com/message/28773#28949

我打了一阵子,希望能帮助别人。

这是因为CoreData框架仍然在Objective-C中。 Swift使用命名空间类,所以CoreDatafind你的swift类,你必须指定类名,它的命名空间是这样的:

在这里输入图像说明

你将遇到的问题是,你的应用程序没有相同的命名空间,当你正在运行你的testing。 <AppName>.<ClassName> vs <AppName>Tests.<ClassName>

编辑:作为应用程序和testing运行的解决scheme

我只写了一段代码来解决<AppName>.<ClassName> vs <AppName>Tests.<ClassName>问题。 我现在使用的解决scheme(Xcode 6.1)是不填充CoreData UI(如上所示)中的Class字段,而是用代码来完成。

此代码将检测您是否正在运行应用程序vstesting并使用正确的模块名称并更新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 }() 

我想我得到了类似的结果给你。 我无法得到我的testing线与工作

 var newDept = NSEntityDescription.insertNewObjectForEntityForName("Department", inManagedObjectContext: moc) as Department 

但是我可以通过以下方式运行testing:

 let entity = NSEntityDescription.entityForName("Department", inManagedObjectContext: moc) let department = Department(entity: entity!, insertIntoManagedObjectContext: moc) 

我的实体看起来像:

 @objc(Department) class Department: NSManagedObject { @NSManaged var department_description: String ... } 

Ludovic的代码示例不包含子实例。 所以当在CoreData中设置父实体时,应用程序崩溃。

修改代码以考虑子实体:

 private func createManagedObjectModel() { // Get module name var moduleName: String = "ModuleName" let environment = NSProcessInfo.processInfo().environment as! [String : AnyObject] let isTest = (environment["XCInjectBundle"] as? String)?.pathExtension == "xctest" if isTest { moduleName = "ModuleNameTests" } // Get model let modelURL = NSBundle.mainBundle().URLForResource(self.storeName, withExtension: "momd")! let model = NSManagedObjectModel(contentsOfURL: modelURL)! // Create entity copies var newEntities = [NSEntityDescription]() for (_, entity) in enumerate(model.entities) { let newEntity = entity.copy() as! NSEntityDescription newEntity.managedObjectClassName = "\(moduleName).\(entity.managedObjectClassName)" newEntities.append(newEntity) } // Set correct subentities for (_, entity) in enumerate(newEntities) { var newSubEntities = [NSEntityDescription]() for subEntity in entity.subentities! { for (_, entity) in enumerate(newEntities) { if subEntity.name == entity.name { newSubEntities.append(entity) } } } entity.subentities = newSubEntities } // Set model self.managedObjectModel = NSManagedObjectModel() self.managedObjectModel.entities = newEntities } 

我也遇到类似的问题,当我试图编写一个示例应用程序( MedicationSchedulerSwift3.0 )在Swift 3.0编写的unit testing用例,除了实现由johnford提供的解决scheme之外,我创build了一个XCTestCase类别来设置NSManagedObjectContext与内存中存储使用下面的代码:

 // XCTestCase+CoreDataHelper.swift import CoreData import XCTest @testable import Medication extension XCTestCase { func setUpInMemoryManagedObjectContext() -> NSManagedObjectContext { let managedObjectModel = NSManagedObjectModel.mergedModel(from: [Bundle.main])! let persistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: managedObjectModel) do { try persistentStoreCoordinator.addPersistentStore(ofType: NSInMemoryStoreType, configurationName: nil, at: nil, options: nil) } catch { print("Adding in-memory persistent store failed") } let managedObjectContext = NSManagedObjectContext(concurrencyType:.privateQueueConcurrencyType) managedObjectContext.persistentStoreCoordinator = persistentStoreCoordinator return managedObjectContext } } 

像这样使用它:

 // NurseTests.swift import XCTest import CoreData @testable import Medication class NurseTests: XCTestCase { var managedObjectContext: NSManagedObjectContext? //MARK: Overriden methods override func setUp() { super.setUp() // Put setup code here. This method is called before the invocation of each test method in the class. if managedObjectContext == nil { managedObjectContext = setUpInMemoryManagedObjectContext() } } //MARK:- Testing functions defined in Nurse.swift // testing : class func addNurse(withEmail email: String, password: String, inManagedObjectContext managedObjectContext: NSManagedObjectContext) -> NSError? func testAddNurse() { let nurseEmail = "clara@gmail.com" let nursePassword = "clara" let error = Nurse.addNurse(withEmail: nurseEmail, password: nursePassword, inManagedObjectContext: managedObjectContext!) XCTAssertNil(error, "There should not be any error while adding a nurse") } } 

如果有人需要更多的例子,他们可以看看这里的unit testing用例 – MedicationTests