使用带有后台进程的模拟Core Data容器

时间:2017-10-09 02:34:02

标签: ios swift unit-testing core-data

我使用使用Core Data的Swift iOS应用程序实现了单元测试,但是我无法通过单元测试。我引用了下面链接的指南和一些堆栈溢出线程,但我仍然遇到问题。

应用程序在实际构建时运行没有缺陷,但测试失败,让我相信我已经搞砸了某个地方,整合了模拟的Core Data容器和后台持久容器。但是,我似乎无法弄清楚我在哪里出错,所以任何建议都值得赞赏。

如果我的帖子缺少任何关键细节,我道歉,但我会在必要时添加它们。

主要参考资料:Cracking the Tests for Core Data

测试代码

class MealTests: XCTestCase {
var sut: MealController!

lazy var managedObjectModel: NSManagedObjectModel = {
    let managedObjectModel = NSManagedObjectModel.mergedModel(from: [Bundle(for: type(of: self))])!
    return managedObjectModel
}()

lazy var mockPersistentContainer: NSPersistentContainer = {
    let container = NSPersistentContainer(name: "WeeklyModel", managedObjectModel: self.managedObjectModel)
    let description = NSPersistentStoreDescription()
    description.type = NSInMemoryStoreType
    description.shouldAddStoreAsynchronously = false

    container.persistentStoreDescriptions = [description]
    container.loadPersistentStores {(description, error) in
        //Double check to confirm that date store is in memory
        precondition(description.type == NSInMemoryStoreType)

        //Check for errors
        if let error = error {
            fatalError("Creating an in-memory coordinator failed")
        }
    }
    return container
}()

override func setUp() {
    super.setUp()

    sut = MealController(tense: .all, persistentContainer: mockPersistentContainer)
}


func test_CreatingNewMeal_IsNotNilAndPropertiesSetCorrectly() {
    let mealType = Int16(1)
    let date = NSDate(timeIntervalSinceNow: 0.0)
    let mealDescription = "Testy McTestFace"
    let servings = Int16(1)
    let image = UIImage(named: "Recipe")
    let favorite = false

    let meal = sut.saveLocalMeal(mealType: mealType, date: date, mealDescription: mealDescription, servings: servings, image: image, favorite: favorite)

    //Test meal is not nil
    XCTAssertNotNil(meal, "Should not be nil")

    //Testing creating meal sets all properties correctly
    XCTAssertEqual(meal?.meal, mealType)
}

控制器类

class MealController {

//MARK: - Properties
//<...>

private let persistentContainer: NSPersistentContainer!

private var fetchedResultsController: NSFetchedResultsController<Meal>!

lazy var backgroundMOC: NSManagedObjectContext = {
    return self.persistentContainer.newBackgroundContext()
}()

 //Set to standard persistence container by default
init(tense: Tense, persistentContainer: NSPersistentContainer) {
    self.persistentContainer = persistentContainer
    self.persistentContainer.viewContext.automaticallyMergesChangesFromParent = true

    reloadAllLocalData(for: tense)
}

convenience init(tense: Tense) {
    guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
        fatalError("Could not set Managed Object Context")
    }
    self.init(tense: tense, persistentContainer: appDelegate.persistenceContainer)
}

func getMealCount() -> Int {
    return fetchedResultsController.fetchedObjects?.count ?? 0
}

func getMeal(at indexPath: IndexPath) -> Meal {
    return fetchedResultsController.object(at: indexPath)
}

//The boolean determines whether historical or future data is shown
func reloadAllLocalData(for tense: Tense){
    let fetchRequest: NSFetchRequest<Meal> = Meal.fetchRequest()

    //Setting predicate, etc.
    //<...>

    fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: backgroundMOC, sectionNameKeyPath: nil, cacheName: nil)//Add cache to this?

    do {
        try fetchedResultsController.performFetch()
    } catch let error {
            //<...>
    }
}

//Saving

func saveLocalMeal(mealType: Int16, date: NSDate, mealDescription: String, servings: Int16, image: UIImage?, favorite: Bool, comment: String? = nil, recipeUID: String? = nil) -> Meal? {

    //Make new meal object
    let meal = Meal(entity: Meal.entity(), insertInto: backgroundMOC)

    //Call helper func and result result
    return save(context: backgroundMOC, meal: meal, mealUID: nil, mealType: mealType, date: date, mealDescription: mealDescription, servings: servings, image: image, favorite: favorite, comment: comment, recipeUID: recipeUID)
}

private func save(context: NSManagedObjectContext, meal: Meal, mealUID: String?, mealType: Int16, date: NSDate, mealDescription: String, servings: Int16, image: UIImage?, favorite: Bool, comment: String? = nil, recipeUID: String? = nil) -> Meal? {

    //Setting properties
    //<...>        

    do {
        try backgroundMOC.save()
        return meal
    } catch let error as NSError {
        print("Could not save. \(error)")
        return nil
    }
}

0 个答案:

没有答案