In testRootContextIsSavedAfterAddingReport() would it have been more clear to use object: derivedContext instead of object: coreDataStack.mainContext in the expectation? They apparently both get NSManagedObjectContextDidSave broadcasts, but it took me a little while to realize this.
Thanks for the feedback, i’m glad you found this article useful.
I am using: let derivedContext = coreDataStack.newDerivedContext()
because it’s a common pattern to create background contexts when saving data so as to not block the UI. Your suggestion is another alternative, however it runs on the main thread which is UI blocking.
I seem to be having trouble with the first few steps. import PandemicReport gets me the error ‘No such module PandemicReport’. When I look at the final project, there seems to be an ‘interface’ representation of CoreDataStack as well as extensions for other models, if you command click' into PandemicReport` and that seems to be the glue that binds the two. How is this file generated? Where is the file located? First foray into unit testing so I am completely open to this being a me thing. As in I should ignore the warnings and just keep going, but I need to understand ‘the root of the root’ as it were to grasp a concept.
Thanks for the feedback @jmstrlr . I have gone through the tutorial just now, starting with the starter project, and unfortunately I am not seeing a 'No such module PandemicReport' error like you are. Could you check out the start project and try the steps again? If you decided to start your own project rather than using the starter project provided, this import will then be the name of your project.
The goal for this tutorial was focused on unit testing Core Data so I have provided a few files to get you started. The CoreDataStack.swift is a custom class provided for you by me and is a wrapper around Core Data. This makes it easier to interact with it and for the testing part of the tutorial.
I believe the extensions you are referring is PandemicReport+CoreDataProperties.swift and PandemicReport+CoreDataClass.swift. This is an NSManagedObject subclass. Using a subclass is a better way to interact with the PandemicReport entity instead of using key-value coding to access the attributes on the PandemicReport. For example,
let location = report.value(forKeyPath: "location")
fetches the location attribute of the PandemicReport entity using key-value coding. Accessing a value using a String is bad practice because it can be prone to human error. Which is why I have used the subclass.
To do the same using an NSManagedObject subclass you would just write the following:
let location = report.location
If you would like to learn more on how to create an NSManagedObject subclass check out this quick tutorial from Apple.
I’m working on a tab controller card collection application with a favorite feature within the application. This tutorial helped me out a lot encapsulating all my CoreData functionalities and added testability within each CRUD functionality.
I do have a question regarding larger applications, How do you manage the same Core Data Stack and ReportService to handle between view controllers in particular tab view controllers. Is a singleton good practice in this case? Having lazy var ReportService within my root view controller to pass within different view controller won’t work since it’s managing its own view context with different models.