4

私は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];
}

これをテストするために、2 つのテスト メソッドを作成しようとしています。

@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

以下は、私が抱えていることがわかっている問題ですが、解決方法がわかりません。

  1. テストに関して管理対象オブジェクトのコンテキストを処理する方法がわかりません。コア データ スタック全体を表示するか、単にモックを作成する必要がありNSManagedObjectContextますか?
  2. if ステートメントをトリガーする方法としてテキスト フィールドの値を設定するという考えは間違っているようです。理想的には、メソッドをスタブアウトして YES または NO を返す必要があると思いますsave:が、質問 1 を考えると、すべてのコア データの側面について確信が持てません。

私は正しい方向に進んでいると思いますが、問題に対処する方法についてセカンドオピニオンを使用し、コード スニペットをテストするための正しい道筋を立てることができます。

4

2 に答える 2

2

ジャスティン、

質問 1 に対して私が行うことは、実際の NSManagedObjectContext を作成することですが、im-memory 永続ストアを作成することです。ディスクには何もヒットせず、真実の CoreData バージョンをテストします。

moc を構築し、永続ストアを初期化する MWCoreDataTest クラス (私の場合は GTMTestCase で拡張) があります。

    - (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 でモックを作成することを検証します

于 2010-02-15T18:23:50.407 に答える
0

何をテストしたいですか?Core Data が保存を行うかどうかをテストしますか? または、アプリケーションが CoreData への呼び出しの結果に正しく応答することをテストしますか?

いずれにせよ、次の行に沿って保存を実行するメソッドを抽出する必要があると思います。

-(BOOL)saveNewItem:(NSString *)itemName error:(NSError **)error { 
    SGItem *newItem = [NSEntityDescription insertNewObjectForEntityForName:kItemEntityName inManagedObjectContext:[self managedObjectContext]];
  newItem.name = itemName;

  NSError *error = nil;
  return[[self managedObjectContext] save:&error];
}

- (IBAction)add:(id)sender {  
  NSString *itemName = [self.itemNameTextField stringValue];
  NSError *error = nil;
  BOOL canSaveNewItem = [self saveNewItem:itemName error:&error];
  if (!canSaveNewItem) {
    [NSApp presentError:error]; 
  }

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

このようにして、インメモリ ストアを設定することで Core Data の保存が期待どおりに機能することをテストでき、ビジネス ロジックを気にする必要はありません。ビジネス ロジックをテストするために、このメソッドの結果をオーバーライドまたはモックすることもできます。

モック化を容易にするために、すべてのコア データを別のクラスに移動して、相互作用をカプセル化することも考えられます。

于 2010-02-15T21:00:48.013 に答える