All the managed object context code is located in my app delegate. Should I have similar 开发者_开发问答code in my unit test classes?
For unit tests, I create an in memory managed object context specifically for the test(s). That way it can be destroyed and recreated for each test in the setUp code and because it's in memory, saves are fast.
** Edit **
The MOC stuff is encapsulated in a class called ModelLoader. I call it from -setUp
of my test like this:
- (void)setUp
{
[super setUp];
loader = [[ModelLoader alloc] initWithName: @"MyDocument"];
NSError* error = nil;
if (![[loader context] save: &error])
{
@throw [NSException exceptionWithName: @"MOCSave"
reason: [error localizedDescription]
userInfo: nil];
}
}
The name is the name of the data model without the .mom
extension. The save and exception throw just rovides a sanity check that makes sure it's all initilised property. By the way, this is GC code. For non GC, you need to release the loader in -tearDown
Relevant code from ModelLoader:
-(id) init
{
return [self initWithName: @"MyDocument"];
}
-(id) initWithName: (NSString*) modelName
{
self = [super init];
if (self != nil)
{
NSBundle* theBundle = [self bundle];
NSURL* modelURL = [theBundle URLForResource: modelName
withExtension: MOM_EXTENSION];
if (modelURL == nil)
{
// log error
}
else
{
model = [[NSManagedObjectModel alloc] initWithContentsOfURL: modelURL];
if (model == nil)
{
// log error
}
}
}
return self;
}
// Create or return the context
-(NSManagedObjectContext*) context
{
if (context == nil)
{
context = [[NSManagedObjectContext alloc] init];
NSPersistentStoreCoordinator* coordinator
= [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self model]];
[context setPersistentStoreCoordinator: coordinator];
NSError* error = nil;
NSPersistentStore* newStore
= [coordinator addPersistentStoreWithType: NSInMemoryStoreType
configuration: nil
URL: nil
options: nil
error: &error];
if (newStore == nil)
{
NSLog(@"Failed to create store, reason %@", error);
context = nil;
}
}
return context;
}
Create a subclass of the code where you create the NSPersistentStoreCoordinator
and override it with a memory store:
- (NSPersistentStoreCoordinator*) coordinator {
if (!_coordinator) {
NSError *error = nil;
_coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self model]];
[_coordinator addPersistentStoreWithType:NSInMemoryStoreType
configuration:nil URL:nil options:nil error:&error];
}
return _coordinator;
}
Or change the path to the store in your persistent manager:
NSPersistentStore *persistentStore = [_coordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error];
Or use the same class, but the downside is that testing requires a known initial state, meaning you want to reset the database before testing, erasing the data you created while using your app.
精彩评论