swift - 单元测试CoreData(+ MagicalRecord)模型触发EXC_BAD_ACCESS

时间:2015-05-15 12:21:50

标签: ios swift unit-testing core-data magicalrecord

我需要对我的一些方法进行单元测试(XCTest),其中包括对CoreData模型的引用。

以下行正确执行:

var airport: AnyObject! = Airport.MR_createEntity()

(lldb) po airport <Airport: 0x7fcf54216940> (entity: Airport; id: 0x7fcf54216a20 <x-coredata:///Airport/t1D3D08DA-70F9-4DA0-9487-BD6047EE93692> ; data: {
    open = nil;
    shortName = nil;
    visible = nil; })

而以下行触发EXC_BAD_ACCESS

var airport2: Airport = Airport.MR_createEntity() as! Airport

(lldb) po airport2
error: Execution was interrupted, reason: EXC_BAD_ACCESS (code=1, address=0x0).
The process has been returned to the state before expression evaluation.

我的主要目标没有出现此错误的迹象。配置是:两个目标中的模型对象,前缀为@objc(MyModel)的类,我xcdatamodel中的类'模型中没有名称空间

知道这里发生了什么吗?

2 个答案:

答案 0 :(得分:3)

是的,所以我终于找到了它的底部并且它不漂亮。这个问题实际上有radar,因为它似乎是Swift编译器无法识别测试目标中的ManagedObject强制转换的错误。所以将你的声音添加到噪音

从定义如下的实体开始:

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

我写了一个简单的测试类,我用3种不同的方式创建MO:

前两个失败了:

let context = NSManagedObjectContext.MR_defaultContext()

func testMagicalRecordCreation() {
    let m = Member.MR_createInContext(context) as? Member
    XCTAssertNotNil(m, "Failed to create object")//fails
}

func testEntityDescriptionClassCreation() {
    let m2 = NSEntityDescription.insertNewObjectForEntityForName("Member", inManagedObjectContext: context) as? Member
    XCTAssertNotNil(m2, "Failed to create object")//fails
}

然后成功

func testManualMOCreation() {
    let ent = NSEntityDescription.entityForName("Member", inManagedObjectContext: context)!
    let m3 = Member(entity: ent, insertIntoManagedObjectContext: context)
    XCTAssertNotNil(m3, "Failed to create object")
}

这意味着您现在有两个选择。在Objective-C中编写测试;或创建一个实用工具方法,使用我在上面显示的方法将测试对象插入上下文。

关于此行为here

的帖子不错

我最终使用NSManagedObjectContext扩展在Swift Tests中显式使用:

extension NSManagedObjectContext {
    func insertTestEntity<T: NSManagedObject>(entity: T.Type) -> T {
        let entityDescription = NSEntityDescription.entityForName(NSStringFromClass(T.self), inManagedObjectContext: self)!
        return T(entity: entityDescription, insertIntoManagedObjectContext: self)
    }
}

它可以像这样使用:

func testConvenienceCreation() {
    let m4 = context.insertTestEntity(Member)
    XCTAssertNotNil(m4, "Failed to create object")
}

更多关于此类方法的阅读here

答案 1 :(得分:0)

有两种方法可以让Swift应用程序类可用于测试目标:

  1. 将您的应用程序类设为公共 - 这包括您要测试的每个变量,常量和函数

  2. 将您的应用程序Swift文件添加到Test目标。这很简单。