开发者

Should unit tests use different managed object context to the main app?

开发者 https://www.devze.com 2023-04-08 18:35 出处:网络
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 specifi

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消