2012-10-02 3 views
1

OCMock을 사용하여 유닛 테스트에서 NSManagedObjects를 모의합니다. 필자는 Mogenerator를 사용하여 핵심 데이터 개체에 대한 기계 및 사람이 읽을 수있는 파일을 생성합니다. 부울 값과 문자열을 반환하기 위해 NSManagedObject를 모의하려고합니다. 둘 다 내 핵심 데이터 엔티티의 속성입니다. BOOL을 조롱하면 객체에서 값이 올바르게 반환되고 클래스에서이를 사용하며 테스트가 성공적으로 통과합니다. 동일한 객체에 NSString 속성을 스텁하려고하면 NSInvalidArgumentException [NSProxy doesNotRecognizeSelector]이 발생합니다. 예외 여기코어 데이터/Mogenerator가있는 OCMock이 예외를 throw합니다. NSInvalidArgumentException [NSProxy doesNotRecognizeSelector]

id biller = [OCMockObject mockForClass:[Biller class]]; 
// passes 
[[[biller stub] andReturnValue:OCMOCK_VALUE((BOOL){NO})] billerValidatedValue]; 
// throws exception 
[[[biller stub] andReturn:@"Test"] name]; 

됩니다 : 여기

가 호출 코드, 테스트 목적으로 NSManagedObject 앞에 앉아 인터페이스를 가지고 some recommendations을 거기에 내가 아는

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSProxy doesNotRecognizeSelector:name] called!' 

하지만, 이것은 Mogenerator 기계/인간 파일의 위에 복잡성을 추가하는 것 같습니다.

이 코드를 완전히 재구성하지 않고이 문제에 대한 다른 제안이 있습니까? 이 코드는 이미 제작 중이며 새로운 기능을 개발할 때 단위 테스트를 추가하려고합니다.

답변

3

문제의 핵심은 테스트에서 핵심 데이터 모델을 사용할 수 없으므로 읽기 속성을 스텁하려고하면 해당 메서드가 존재하지 않는다는 것입니다. 핵심 데이터는 런타임에 속성 접근자를 동적으로 차단합니다.

모델을 사용할 수있게하려면 .xcdatamodeld가 단위 테스트 대상에 포함되어 있고 테스트에서 모델을 설정해야합니다. 동적 속성을 모의 할 수 있을지 확신 할 수 없지만 테스트에서 Core Data 객체에 대해 CRUD 작업을 수행하는 것은 간단하므로 모방 할 필요가 없습니다.

static NSManagedObjectModel *model; 
static NSPersistentStoreCoordinator *coordinator; 
static NSManagedObjectContext *context; 
static NSPersistentStore *store; 

-(void)setUp { 
    [super setUp]; 
    if (model == nil) { 
     @try { 
      NSString *modelPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"my-model" ofType:@"mom"]; 
      NSURL *momURL = [NSURL fileURLWithPath:modelPath]; 
      model = [[NSManagedObjectModel alloc] initWithContentsOfURL:momURL]; 
     } 
     @catch (NSException *exception) { 
      NSLog(@"couldn't get model from bundle: %@", [exception reason]); 
      @throw exception; 
     } 
    } 
    coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model]; 
    NSError *error; 
    store = [coordinator addPersistentStoreWithType: NSInMemoryStoreType 
             configuration: nil 
               URL: nil 
              options: nil 
               error: &error]; 
    assertThat(store, isNot(nil)); 
    context = [[NSManagedObjectContext alloc] init]; 
    [context setPersistentStoreCoordinator:coordinator]; 
} 

-(void)tearDown { 
    // these assertions ensure the test was not short-circuited by a failure to initialize the model 
    assertThat(model, isNot(nil)); 
    assertThat(context, isNot(nil)); 
    assertThat(store, isNot(nil)); 
    assertThat(coordinator, isNot(nil)); 
    NSError *error = nil; 
    STAssertTrue([coordinator removePersistentStore:store error:&error], 
       @"couldn't remove persistent store: %@", [error userInfo]); 
    [super tearDown]; 
} 

다른 방법으로, MagicalRecord를 사용하여 크게 일을 단순화 할 수 있습니다 : 여기에 귀하의 테스트에서 모델을 초기화하는 방법 중 하나입니다. 앱에서 사용하지 않더라도 테스트에 사용하여 모든 핵심 데이터 설정을 캡슐화 할 수 있습니다. 다음은 MagicalRecord가 포함 된 앱에서 단위 테스트 설정이 어떻게 표시되는지 보여줍니다.

+0

나는 이것을 처음부터 알고 싶습니다. 나는 MagicalRecord를 테스트 용 메모리 저장소와 함께 사용한다. 그리고 당신이 지적한 것처럼 각 테스트를 수행하기 전에 db를 리셋한다. 관리 객체를 조롱하는 대신에 방금 사용 했어야했습니다. 철저한 답변 주셔서 감사합니다! –