简体   繁体   English

具有多个实体的单元测试核心数据

[英]Unit test core data with multiple entities

I would like to test my core data methode.我想测试我的核心数据方法。 There is multiples entities in my coredataModel and for each I have a NSManagedObject class there is methode inside those classes to add, delete and remove data of the corresponding entity.我的 coredataModel 中有多个实体,每个实体都有一个 NSManagedObject class 在这些类中有添加、删除和删除相应实体数据的方法。

public class StoredGame: NSManagedObject {

    static private let storage = DataManager.shared.storage

    static var all: [Game] {
        let request: NSFetchRequest<StoredGame> = StoredGame.fetchRequest()
        guard let storedGame = try? storage.viewContext.fetch(request) else { return [] }
        var games: [Game] = .init()

        storedGame.forEach { (storedGame) in
            games.append(convert(storedGame))
        }
        return games
    }

    static func add(new game: Game) {
        let entity = NSEntityDescription.entity(forEntityName: "StoredGame", in: storage.viewContext)!
        let newGame = StoredGame(entity: entity, insertInto: storage.viewContext)
        try? storage.saveContext()
    }
}

and then I have a class responsible of the core data stack然后我有一个负责核心数据堆栈的 class

    class CoreDataManager {

        private lazy var persistentContainer: NSPersistentContainer! = {
            guard let modelURL = Bundle.main.url(forResource: "CoreData", withExtension:"momd") else {
                fatalError("Error loading model from bundle")
            }
            // The managed object model for the application. It is a fatal error for the application not to be able to find and load its model.
            guard let mom = NSManagedObjectModel(contentsOf: modelURL) else {
                fatalError("Error initializing mom from: \(modelURL)")
            }
            let container = NSPersistentContainer(name: "CoreData", managedObjectModel: mom)
            container.loadPersistentStores(completionHandler: { (storeDescription, error) in
                if let error = error as NSError? {
                    fatalError("Unresolved error \(error), \(error.userInfo)")
                }
            })
            return container
        }()

        var viewContext: NSManagedObjectContext {
            return persistentContainer.viewContext
        }

        func saveContext () throws {
            let context = viewContext
            if context.hasChanges {
                do {
                    try context.save()
                } catch(let error) {
                    print(error)
                }
            }
        }
    }

Then when it goes to the tests.然后当它进行测试时。 I've created a mockContainer and a mockCoreData我创建了一个 mockContainer 和一个 mockCoreData

   lazy var mockContainer: NSPersistentContainer = {
        let container = NSPersistentContainer(name: "CoreData")
        container.persistentStoreDescriptions[0].url = URL(fileURLWithPath: "/dev/null")
        container.loadPersistentStores(completionHandler: { (_, error) in
            XCTAssertNil(error)
        })
        return container
    }()

    lazy var mockCoreData = {
        return StoredGame(context: mockContainer.viewContext)
    }()

So now I dont know how to run tests in that configuration, I've tried a所以现在我不知道如何在该配置中运行测试,我尝试了

XCTAssert(StoredGame.all.isEmpty) for exemple ( i have a all var in the StoredEntity class) XCTAssert(StoredGame.all.isEmpty)例如(我在 StoredEntity 类中有一个 all var)

but it fails with an error telling但它失败并出现错误提示

'NSInvalidArgumentException', reason: '-[CoreData.StoredEntity setId:]: unrecognized selector sent to instance

any idea?任何想法?

This might be occurring with passing an invalid URL for the store description.为商店描述传递无效的 URL 可能会发生这种情况。 Unless you need to run tests with a NSSQLiteStoreType, which is the default for NSPersistentContainer , you may want to consider using an NSInMemoryStoreType for unit testing.除非您需要使用 NSSQLiteStoreType(这是NSPersistentContainer的默认值)运行测试,否则您可能需要考虑使用 NSInMemoryStoreType 进行单元测试。 A small tweak to your CoreDataManager class could allow you to initialize the class both for your app and unit tests.对您的CoreDataManager进行一个小调整可以让您为您的应用程序和单元测试初始化 class。 For example:例如:

class CoreDataManager {

    private let persisted: Bool

    init(persisted: Bool = true) {
        self.persisted = persisted
    }

    lazy var persistentContainer: NSPersistentContainer = {
        let description = NSPersistentStoreDescription()
        if persisted {
            description.type = NSSQLiteStoreType
            description.url = // location to store the db.
        } else {
            description.type = NSInMemoryStoreType
        }

        let container = NSPersistentContainer(name: "CoreData")
        container.persistentStoreDescriptions = [description]
        container.loadPersistentStores //...
        return container
    }()

}

Then you can use this exact class in your unit tests without need to create a mock.然后,您可以在单元测试中使用这个精确的 class 而无需创建模拟。 Just initialize it without persistence:只需初始化它而无需持久性:

let manager = CoreDataManager(persisted: false)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM