【问题标题】:How to Use Core Data Models with In-Memory Store Type Using Prepopulated SQLite File?如何使用预填充的 SQLite 文件使用具有内存存储类型的核心数据模型?
【发布时间】:2017-04-11 20:57:22
【问题描述】:

我正在关注 Ray Wenderlich 团队的一个过时的 tutorial,该团队使用命令行工具应用程序重新填充了一个支持 Core Data 的应用程序。

我已成功预填充预期的实体,并通过执行NSFetchRequest 进行验证。

现在,我想在我的单元测试中使用相同的预填充数据来验证我与CoreData 的交互是否正确发生。我尝试设置我的模拟CoreDataStack 子类以使用内存存储,但是当我尝试验证我有用于单元测试的预填充数据时,我得到了count0

负责与我的应用程序目标中的CoreData 交互的类名为CoreDataStack,如下:

/// The object that is responsible for managing interactions with Core Data.
internal class CoreDataStack {

    // MARK: - Properties

    /// The name of the `NSManagedObjectModel` object used for storing information with Core Data.
    private let modelName: String

    /// The `NSManagedObjectContext` object that is associated with the main queue.
    internal lazy var mainContext: NSManagedObjectContext = {
        return self.storeContainer.viewContext
    }()

    /// The `NSPersistentContainer` object that encapsulates the application's Core Data stack.
    internal lazy var storeContainer: NSPersistentContainer = {
        let container = NSPersistentContainer(name: self.modelName)
        let directory = NSPersistentContainer.defaultDirectoryURL()
        let storeURL = directory.appendingPathComponent("\(self.modelName).sqlite")
        if !FileManager.default.fileExists(atPath: (storeURL.path)) {
            guard let populatedURL = Bundle.main.url(forResource: self.modelName, withExtension: "sqlite") else {
                fatalError("Invalid populated .sqlite file URL")
            }
            do {
                try FileManager.default.copyItem(at: populatedURL, to: storeURL)
            } catch {
                fatalError("Error: \(error)")
            }
        }
        let description = NSPersistentStoreDescription()
        description.url = storeURL
        container.persistentStoreDescriptions = [description]
        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error as NSError? {
                fatalError("Error: \(error)")
            }
        })
        return container
    }()

    // MARK: - Initialization

    /// Returns an instance of `CoreDataStack`.
    /// - parameter modelName: The name of the `NSManagedObjectModel` object used for storing information with Core Data.
    internal init(modelName: String) {
        self.modelName = modelName
    }

    /// Attempts to save items to Core Data by committing changes to `NSManagedObject`s in a `NSManagedObjectContext`.
    /// - parameter context: The `NSManagedObjectContext` of which changes should be committed.
    internal func saveContext(_ context: NSManagedObjectContext) {
        context.perform {
            do {
                try context.save()
            } catch let error as NSError {
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        }
    }
}

CoreDataStackMockCoreDataStack的子类,用于测试如下:

internal class MockCoreDataStack: CoreDataStack {

    // MARK: - Initialization

    convenience init() {
        self.init(modelName: "Currency")
    }

    override init(modelName: String) {
        super.init(modelName: modelName)
        let container = NSPersistentContainer(name: modelName)
        let directory = NSPersistentContainer.defaultDirectoryURL()
        let storeURL = directory.appendingPathComponent("\(modelName).sqlite")
        if !FileManager.default.fileExists(atPath: (storeURL.path)) {
            guard let populatedURL = Bundle(for: type(of: self)).url(forResource: modelName, withExtension: "sqlite") else {
                fatalError("Invalid populated .sqlite file URL")
            }
            do {
                try FileManager.default.copyItem(at: populatedURL, to: storeURL)
            } catch {
                fatalError("Error: \(error)")
            }
        }
        let description = NSPersistentStoreDescription()
        description.url = storeURL
        description.type = NSInMemoryStoreType
        container.persistentStoreDescriptions = [description]
        container.loadPersistentStores { (storeDescription, error) in
            if let error = error as NSError? {
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        }
        self.storeContainer = container
    }
}

在我的单元测试目标中,我的 fetch 请求的结果 count0。我希望返回一个包含预填充对象数量的 count,就像我在应用程序的目标中返回 count 时得到的一样。

我做错了什么导致我没有返回预期的结果?

【问题讨论】:

    标签: unit-testing core-data


    【解决方案1】:

    内存存储不使用存储 URL。它只是在内存中创建一个空存储。

    作为内存存储的替代方案,您可以在持久存储和您实际使用的上下文之间创建父 NSManagedObjectContext。 (不过,我不确定 NSPersistentContainer 会如何发挥作用。)

    然后,当您想重置回初始状态时,您只需 rollback() 父上下文即可。

    【讨论】:

      猜你喜欢
      • 2011-05-19
      • 1970-01-01
      • 1970-01-01
      • 2017-01-10
      • 2011-09-29
      • 1970-01-01
      • 2015-07-04
      • 2013-10-26
      • 2012-01-10
      相关资源
      最近更新 更多