Remember from Core Data Fundamentals that we need a managed object context to instantiate a managed object. To freshen up your memory, this is what it takes to create a note.
let note = Note(context: managedObjectContext)
This implies that we need a Core Data stack. If you're watching this episode, then I assume you already know how to do that. We have several options. We could follow the recipe from Core Data Fundamentals by creating a Core Data stack with a SQLite database as the persistent store. This is fine, but there's a solution that's better suited for unit testing Core Data models. To unit test the Core Data models of a project, we choose for an in-memory store as the persistent store. What is an in-memory store and why is it the preferred choice?
We want to start with a clean slate before a unit test is run. But we don't want to create and delete a SQLite database every time. It's slow and cumbersome. By using an in-memory store as the persistent store of the Core Data stack, we don't need to worry about creating and deleting the persistent store. As the name implies, the data stored in an in-memory store is only kept in the machine's memory and that's what makes it an interesting option for writing fast and reliable unit tests for Core Data models.
Creating an Extension
Because we plan to create a Core Data stack in several XCTestCase subclasses, I'd like to start by creating an extension on the XCTestCase class that helps us with this task. This is easier than you might think. Create a Swift file in the Extensions group of the NotesTests target and name it XCTestCase.swift.

If Xcode offers you to create an Objective-C bridging header, then choose to not create one. We don't need an Objective-C bridging header for this project.

Add an import statement for the XCTest and CoreData frameworks at the top and create an extension for the XCTestCase class.
XCTestCase.swift
import XCTest
import CoreData
extension XCTestCase {
}
Even though we intend to create a functional Core Data stack, we only need a managed object context to write the unit tests for the Core Data models. We define a method, setupCoreDataStack(with:in:), which returns an instance of the NSManagedObjectContext class.
XCTestCase.swift
// MARK: - Core Data
func setupCoreDataStack(with name: String, `in` bundle: Bundle) -> NSManagedObjectContext {
}
The method defines two parameters, the name of the data model and the bundle the data model belongs to. It's useful to specify the bundle because the unit testing bundle is different from the Notes bundle.
The implementation of the setupCoreDataStack(with:in:) method is easy to understand. Setting up a Core Data stack with an in-memory store as the persistent store is a bit simpler since we don't need to specify the location of the persistent store. Remember that no data is written to a physical location on disk. We first create the managed object model by loading the compiled version of the data model.
XCTestCase.swift
// Fetch Model URL
let modelURL = bundle.url(forResource: name, withExtension: "momd")!
// Initialize Managed Object Model
let managedObjectModel = NSManagedObjectModel(contentsOf: modelURL)!
Notice that we make ample use of the exclamation mark. Remember that we're not interested in safety when we're writing unit tests. If we're unable to load the data model, we made a mistake we need to fix. In other words, we're not interested in error handling or safety when writing and running unit tests. If something goes wrong, the unit tests fail anyway.
We initialize a persistent store coordinator with the managed object model and add a persistent store to the persistent store coordinator. The first argument of addPersistentStore(ofType:configurationName:at:options:) is NSInMemoryStoreType. In other words, we instruct Core Data to add an in-memory store as the persistent store.
XCTestCase.swift
// Initialize Persistent Store Coordinator
let persistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: managedObjectModel)
// Add Persistent Store
try! persistentStoreCoordinator.addPersistentStore(ofType: NSInMemoryStoreType, configurationName: nil, at: nil, options: nil)
Because we use an in-memory store, there's no need to specify a location for the persistent store. We also don't pass in a configuration name or a dictionary of options.
We use the try keyword with an exclamation mark. This is something I only ever do when writing unit tests. You have to understand that we're only interested in the results of the unit tests as I mentioned earlier. Safety takes a back seat. The focus is speed and readability.
We now have the ingredients we need to create a managed object context. We invoke the designated initializer of the NSManagedObjectContext class and pass in mainQueueConcurrencyType as the concurrency type for the managed object context. We configure the managed object context by setting its persistentStoreCoordinator property.
XCTestCase.swift
// Initialize Managed Object Context
let managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
// Configure Managed Object Context
managedObjectContext.persistentStoreCoordinator = persistentStoreCoordinator
return managedObjectContext
This is what the implementation of the setupCoreDataStack(with:in:) method looks like.
XCTestCase.swift
func setupCoreDataStack(with name: String, `in` bundle: Bundle) -> NSManagedObjectContext {
// Fetch Model URL
let modelURL = bundle.url(forResource: name, withExtension: "momd")!
// Initialize Managed Object Model
let managedObjectModel = NSManagedObjectModel(contentsOf: modelURL)!
// Initialize Persistent Store Coordinator
let persistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: managedObjectModel)
// Add Persistent Store
try! persistentStoreCoordinator.addPersistentStore(ofType: NSInMemoryStoreType, configurationName: nil, at: nil, options: nil)
// Initialize Managed Object Context
let managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
// Configure Managed Object Context
managedObjectContext.persistentStoreCoordinator = persistentStoreCoordinator
return managedObjectContext
}
Ready, Set, Test
Let's put the setupCoreDataStack(with:in:) method to use. Create a new file in the Test Cases group, choose the Unit Test Case Class template, and name the file NoteTests.swift.


Add an import statement for the Core Data framework and an import statement for the Notes module. To gain access to internal entities of the Notes module, we need to prefix the import statement for the Notes module with the testable attribute.
NoteTests.swift
import XCTest
import CoreData
@testable import Notes
class NoteTests: XCTestCase {
}
We define a private, variable property for the managed object context we'll be using in the unit tests for the Note class.
NoteTests.swift
// MARK: - Properties
private var managedObjectContext: NSManagedObjectContext!
Notice that the property, managedObjectContext, is an implicitly unwrapped optional. Why is that? As I mentioned earlier, we're not concerned with safety when we write unit tests. We're only interested in the results of the unit tests. If anything goes wrong, then we want to know about it and it means we made a mistake we need to fix. Unit tests need to be fast and readable. That's the primary focus when we write unit tests.
In the setUp() method of the XCTestCase subclass, we invoke the setupCoreDataStack(with:in:) method, passing in Notes as the first argument and a reference to the main bundle as the second argument. We store the return value in the managedObjectContext property we defined earlier.
NoteTests.swift
// MARK: - Set Up & Tear Down
override func setUp() {
super.setUp()
// Create Managed Object Context
managedObjectContext = setupCoreDataStack(with: "Notes", in: Bundle.main)
}
In the tearDown() method, we tear down the Core Data stack by setting the managedObjectContext property to nil. Tearing down the Core Data stack isn't strictly necessary since this automatically happens when a unit test has finished running. However, it's a good practice to use the setUp() and tearDown() methods to perform such operations. That's what they're designed for, setting up and tearing down the test environment before and after a unit test. It makes it much clearer what's happening before and after a unit test is run.
NoteTests.swift
override func tearDown() {
super.tearDown()
// Clean Up
managedObjectContext = nil
}
Remove the unit tests Xcode has created for us and run the test suite to make sure everything works as expected. You shouldn't see any errors or warnings.
What's Next?
With the Core Data stack in place, it's time to write the first unit test for the Note class. That's the focus of the next episode.