使用简单的 init 在测试中创建 CoreData 对象

Posted

技术标签:

【中文标题】使用简单的 init 在测试中创建 CoreData 对象【英文标题】:Create CoreData object in tests with a simple init 【发布时间】:2019-04-04 12:56:01 【问题描述】:

我有一组NSManagedObject 子类供ClassToBeTested 使用。

ClassToBeTested 仅对 NSManagedObject 子类的几个属性进行操作,不需要关系或整个 CoreData 堆栈。

我可以通过以常规方式创建它们以某种方式在测试中使用相同的对象吗:

        let template = CoreDataClass()
        template.name = randomString(length: 40) // This fails!
        templates.append(template)

目前它失败并出现错误:

失败:捕获“NSInvalidArgumentException”,“-[CoreDataClass setTemplate_name:]: 无法识别的选择器发送到实例 0x600000af4c40"

【问题讨论】:

【参考方案1】:

虽然我在尝试这样做时遇到了不同的错误(没有调用指定的初始化程序),但无论哪种情况,您的问题的答案都是:不,您不能这样做。 p>

但是现在有了 NSPersistentContainer,很容易使用单例内存中的核心数据堆栈进行此类测试。将您的数据模型包含在您的测试包中,然后将其放入您的测试的全局范围内:

var sharedTestContext: NSManagedObjectContext = 
    // Swift is smart enough to execute this only once.
    let container = NSPersistentContainer(name: "<YourDataModelName>")
    let description = NSPersistentStoreDescription()
    description.type = NSInMemoryStoreType
    container.persistentStoreDescriptions = [description]
    container.loadPersistentStores  (description, error) in
        if let error = error 
            fatalError("Failed to load store for test: \(error)")
        
    
    return container.newBackgroundContext()
()

并定义一个特殊的托管对象初始化器用于测试,如下所示:

/**
 Initializes a managed object for testing

 - important:  This assumes your managed object subclass name is the same
 as its entity name.
 */
public extension NSManagedObject 
    convenience init(testContext: NSManagedObjectContext?) 
        let context = testContext ?? sharedTestContext
        /*  The following contraption is necessary to avoid warning:
         "Multiple NSEntityDescriptions claim the NSManagedObject subclass"
         For explanation see:
         https://***.com/questions/51851485/multiple-nsentitydescriptions-claim-nsmanagedobject-subclass */
        let name = String(describing: type(of: self))
        let entity = NSEntityDescription.entity(forEntityName: name, in: context)!
        self.init(entity: entity, insertInto: context)
    

现在你可以这样创建你的测试对象了:

let template = CoreDataClass(testContext: nil)

【讨论】:

以上是关于使用简单的 init 在测试中创建 CoreData 对象的主要内容,如果未能解决你的问题,请参考以下文章

在目标 c 中创建简单的 OCMock 单元测试

如何为仅在测试中可见的结构创建 init 方法?

如何使用 init.sql 在 Postgresql 中创建数据库、模式和表

如何使用不同的 init 方法在 XIB 中创建自定义视图?

如何在 Cypress 中创建基本的普通测试报告

在jmeter测试计划中创建多个线程组