在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应用程序的模块名称不同(即App
和AppTests
确保您在每个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
)