objective-c – 使用OCMock和Core Data测试控制器方法

我只是抓住了TDD和嘲讽的概念,并且在如何正确处理问题上遇到了问题.我有一张下拉的工作表,让用户创建一个新的核心数据对象并将其保存到数据存储中.我不确定我是否采用最佳方法进行测试.

- (IBAction)add:(id)sender 
{  
  NSString *itemName = [self.itemNameTextField stringValue];
  SGItem *newItem = [NSEntityDescription insertNewObjectForEntityForName:kItemEntityName inManagedObjectContext:[self managedObjectContext]];
  newItem.name = itemName;

  NSError *error = nil;
  BOOL canSaveNewItem = [[self managedObjectContext] save:&error];
  if (!canSaveNewItem) 
  {
    [NSApp presentError:error]; 
  }

  [self clearFormFields];  // Private method that clears text fields, disables buttons
  [NSApp endSheet:[self window] returnCode:NSOKButton];
}

我正在尝试编写两种测试方法来测试它:一种测试托管对象无法保存的场景,另一种是成功保存的场景.

@interface SGAddItemWindowControllerTests : SGTestCase 
{
@private
  SGAddItemWindowController *addItemWindowController;
  id mockApp;
  id mockNameField;
}

- (void)setUp 
{
  mockNameField = [OCMockObject mockForClass:[NSTextField class]];
  mockApp = [OCMockObject mockForClass:[NSApplication class]];

  addItemWindowController = [[BLAddItemWindowController alloc] init];  
  [addItemWindowController setValue:mockNameField forKey:@"itemNameTextField"];
}

- (void)testAddingNewItemFromSheetFailed
{
  // Setup
  NSString *fakeName = @"";
  [[[mockNameField expect] andReturn:fakeName] stringValue];
  [[mockApp expect] presentError:[OCMArg any]];

  // Execute
  [addItemWindowController add:nil];

  // Verify
  [mockApp verify];
}

- (void)testAddingNewItemFromSheetSucceeds
{
  // Setup
  NSString *fakeName = @"Item Name";
  [[[mockNameField expect] andReturn:fakeName] stringValue];
  [[mockApp expect] endSheet:[OCMArg any] returnCode:NSOKButton];

  // Execute
  [addItemWindowController add:nil];

  // Verify
  [mockApp verify];
  [mockNameField verify];
}

@end

以下是我所知道的问题,但我不确定如何解决:

>我不确定如何在测试方面处理托管对象上下文.我应该调出整个核心数据堆栈还是只创建NSManagedObjectContext的模拟?
>将文本字段值设置为触发if语句的方法的想法似乎是错误的.理想情况下,我认为我应该删除save:方法并返回YES或NO,但是给出问题1我不确定核心数据方面的所有内容.

我想我已走上正轨,但我可以就如何解决我的问题使用第二意见,并让我走上正确的路径来测试代码片段.

最佳答案 贾斯汀,

我为问题#1做的是创建一个实际的NSManagedObjectContext,但创建一个内存持久性存储.什么都没有击中磁盘,我测试了CoreData版本的真相.

我有一个MWCoreDataTest类(在我的案例中扩展为GTMTestCase),它构建了moc并初始化了持久性存储

    - (NSManagedObjectContext *) managedObjectContext {

    if (managedObjectContext != nil) {
        return managedObjectContext;
    }

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (coordinator != nil) {
        managedObjectContext = [[NSManagedObjectContext alloc] init];
        [managedObjectContext setPersistentStoreCoordinator: coordinator];
    }

    return managedObjectContext;
}



- (NSPersistentStoreCoordinator*)persistentStoreCoordinator;
{
    if (persistentStoreCoordinator) return persistentStoreCoordinator;
    NSError* error = nil;
    NSManagedObjectModel *mom = [self managedObjectModel];
    persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc]
                                  initWithManagedObjectModel:mom];


    if (![persistentStoreCoordinator addPersistentStoreWithType:NSInMemoryStoreType
                                                  configuration:nil
                                                            URL:nil
                                                        options:nil
                                                          error:&error]) {
        [[NSApplication sharedApplication] presentError:error];
        return nil;
    }
    return persistentStoreCoordinator;
}

WRT#2,我认为没关系 – 如果你计划在课堂上测试多个行为,那就移动吧

[addItemWindowController setValue:mockNameField forKey:@"itemNameTextField"];

到testAdding ..方法

如果你解决了#1,那么你可以将itemNameText字段设置为nil,然后触发保存验证.

WRT#3,我将验证在NSApp上构建模拟===在NSApplication上构建模拟

点赞