CoreData类在单元测试中未匹配

时间:2014-11-25 17:02:03

标签: ios unit-testing core-data swift

当我尝试从模型中检索项目数组时,由于类的类型不匹配,我总是会遇到向下转换错误。 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")
}

当我运行测试时,以下类型将显示在调试器中:

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

所以看起来result数组包含的Boss类项目与bosses不匹配 阵列。

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

您将在github上找到完整的项目。

4 个答案:

答案 0 :(得分:4)

如果你改变了

if let downcastedSwiftArray = results as? [Boss] {

迫使向下转发

if let downcastedSwiftArray = results as! [Boss] {

由于运行时错误导致测试中止吗?

我也有向下转换到Core Data托管对象类型的问题。将NSManagedObject sublcasses'文件添加到测试目标使得代码编译但似乎无法正常工作。 因此,不要将测试中的代码添加到测试目标本身。导入它。

使用Swift 2:使用@testable

在Swift引入@testable import之前,我们被迫制作了我们想要公开测试的课程。这比我们想要的客户端暴露了更多的代码。如今,这是要走的路。

在Swift 2之前:公开课

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

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

然后在测试中导入生产模块:

import MyProjectTargetName

答案 1 :(得分:3)

使您的类public是一种解决方法,不应该用于测试依赖项。

问题实际上是测试目标编译了他自己的源类版本,这不是你想要的。你最终会得到两个相同的版本。

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

删除所有'正常'测试目标编译列表中的类

enter image description here

确保应用和测试应用的模块名称不同(即AppAppTests

enter image description here enter image description here

确保在每次测试中导入app模块

enter image description here

答案 2 :(得分:0)

在Swift中,您必须指定由获取请求产生的数组的类型。 if let模式需要一个可选的强制转换。

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

答案 3 :(得分:0)

解决此问题的一种方法是使用以下内容动态更改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!)"
    }

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