Основные данные модульного тестирования с несколькими объектами - PullRequest
0 голосов
/ 06 мая 2020

Я хотел бы протестировать свой метод основных данных. В моей модели coredataModel есть несколько сущностей, и для каждого класса NSManagedObject есть метод внутри этих классов для добавления, удаления и удаления данных соответствующего объекта.

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()
    }
}

, а затем у меня есть класс, отвечающий за стек данных ядра

    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)
                }
            }
        }
    }

Потом когда идет на тесты. Я создал 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)
    }()

Итак, теперь я не знаю, как запускать тесты в этой конфигурации, я пробовал

XCTAssert(StoredGame.all.isEmpty), например (у меня a all var в классе StoredEntity)

, но это не удается с сообщением об ошибке

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

любая идея?

1 Ответ

0 голосов
/ 06 мая 2020

Это могло произойти при передаче недопустимого URL-адреса для описания магазина. Если вам не нужно запускать тесты с NSSQLiteStoreType, который используется по умолчанию для NSPersistentContainer, вы можете рассмотреть возможность использования NSInMemoryStoreType для модульного тестирования. Небольшая настройка вашего класса CoreDataManager может позволить вам инициализировать класс как для вашего приложения, так и для модульных тестов. Например:

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
    }()

}

Затем вы можете использовать именно этот класс в своих модульных тестах без необходимости создавать имитацию. Просто инициализируйте его без сохранения:

let manager = CoreDataManager(persisted: false)
...