在unit testing中CoreData类错过匹配

当我尝试从我的模型中检索项目的数组时,我总是得到一个向下的转换错误,因为类的types不匹配。 Swift有一个严格的命名空间,模型项目与我想要的项目不同。 这是我的NSManagedObject:

import Foundation import CoreData @objc(Boss) class Boss: NSManagedObject { @NSManaged var name: String } 

Testclass如下:

 func testCheckIfFetchGetTheCorrectClass() { // setup item let entity = NSEntityDescription.entityForName("Boss", inManagedObjectContext: moc) let boss = Boss(entity: entity!, insertIntoManagedObjectContext: moc) boss.name = "Chef" var bosses = [Boss]() var request = NSFetchRequest(entityName: "Boss") var e: NSError? if let results = moc.executeFetchRequest(request, error: &e) { println("results: \n\(results.description)\nCount:\(results.count)") if let downcastedSwiftArray = results as? [Boss] { // downcastedSwiftArray contains only UIView objects bosses = downcastedSwiftArray } else { XCTAssert(false, "Down Cast Error") } println("Bosses : \n\(bosses.description)") } else { println("fetch error: \(e!.localizedDescription)") abort(); } // This is an example of a functional test case. XCTAssert(true, "Pass") } 

当我运行testing以下types将显示在debugging器中:

 bosses [NameSpaceTestTests.Boss] 0 values results [AnyObject] 1 value [0] Boss_Boss_ * 

所以看起来像result数组包含一个Boss类项目将不匹配bosses数组。

我如何分配获取请求的结果到我的数组?

你会在github上find完整的项目。

public你的类是一个解决方法,不应该需要testing依赖。

问题的实质是testing目标编译自己的源代码版本,这不是你想要的。 你会得到两个相同的版本。

以下步骤为我解决了这个问题:

从testing目标编译列表中删除所有“正常”类

在这里输入图像说明


确保应用程序和testing应用程序的模块名称不同(即AppAppTests

在这里输入图像说明 在这里输入图像说明


确保您在每个testing中导入应用程序模块

在这里输入图像说明

如果你改变

 if let downcastedSwiftArray = results as? [Boss] { 

强迫沮丧

 if let downcastedSwiftArray = results as! [Boss] { 

由于运行时错误,您的testing中止吗?

我也有问题向下转换为Core Datapipe理对象types。 添加NSManagedObject sublcasses的文件到testing目标代码编译,但似乎没有正常工作。 所以不要将testing中的代码添加到testing目标本身。 导入它。

使用Swift 2:使用@testable

在Swift引入@testable import之前,我们被迫做了我们想要公开testing的类。 这暴露了我们更多的代码给客户端比我们想要的。 现在,这是要走的路。

Swift 2之前:公开课

我通过public课程来解决这个问题:

 @objc(Boss) public class Boss: NSManagedObject { @NSManaged public var name: String } 

然后在testing中导入生产模块:

 import MyProjectTargetName 

在Swift中,你必须指定从一个获取请求产生的数组的types。 如果让模式需要一个可选的演员。

 if let result = moc.executeFetchRequest(request, error:&e) as? [Boss] { // use result } 

解决这个问题的一个方法是dynamic地改变NSManagedObject子类的类名,如下所示:

  let managedObjectModel = NSManagedObjectModel.mergedModelFromBundles([NSBundle.mainBundle()])! // Check if it is within the test environment let environment = NSProcessInfo.processInfo().environment as! [String : AnyObject] let isTestEnvironment = (environment["XCInjectBundle"] as? String)?.pathExtension == "xctest" // Create the module name based on product name let productName:String = NSBundle.mainBundle().infoDictionary?["CFBundleName"] as! String let moduleName = (isTestEnvironment) ? productName + "Tests" : productName let newManagedObjectModel:NSManagedObjectModel = managedObjectModel.copy() as! NSManagedObjectModel for entity in newManagedObjectModel.entities as! [NSEntityDescription] { entity.managedObjectClassName = "\(moduleName).\(entity.name!)" } 

这有助于解决类名称不匹配的问题,因为在运行testing时,类名实际上是<Product Name>Tests.<Subclass Name> (在你的情况下,它是NameSpaceTestTests.Boss