Базовое тестирование модуля данных - не знаете, как вызвать ошибку в executeFetchRequest: error: - PullRequest
5 голосов
/ 21 февраля 2012

Согласно NSManagedObjectContext Class Documentation ...

- (NSArray *)executeFetchRequest:(NSFetchRequest *)request error:(NSError **)error

Возвращаемое значение

Массив объектов, которые соответствуюткритерии, указанные в запросе, полученном от получателя и из постоянных хранилищ, связанных с координатором постоянного хранилища получателя.Если возникает ошибка, возвращает ноль.Если ни один объект не соответствует критерию, указанному в запросе, возвращает пустой массив.

Я пытаюсь создать модульный тест для ситуации «в случае ошибки возвращается ноль».

Я бы хотел избежать использования OCMock (или создания подкласса NSManagedObjectContext для переопределения executeFetchRequest: error: метод), потому что я считаю, что есть простой способ обеспечить отказ этого метода.Пока мой модульный тест читает ...

- (void)testReportingCoreDataErrorToDelegate
{
    NSManagedObjectContext *badContext = [[NSManagedObjectContext alloc] init];

    [bcc setManagedObjectContext:badContext];
    [bcc fetchFromCoreData];
    STAssertTrue([mockDelegate didReceiveCoreDataError], @"This never asserts, it fails because the fetch request couldn't find an entity name - i.e. no managed object model");
}

Есть ли простой способ вызвать запрос на выборку, возвращающий nil?

Ответы [ 2 ]

4 голосов
/ 08 января 2013

У меня была такая же загадка. Мне нравится держать покрытие юнит-тестов на 100%, когда это возможно. Нет простого способа сгенерировать состояние органической ошибки. На самом деле, я не уверен, что текущая реализация четырех типов хранилищ, которые поставляются с Core Data, ever вызовет ошибку в ответ на executeFetchRequest: error. Но как это могло произойти в будущем, вот что я сделал:

У меня есть один файл с примерами модульных тестов, который посвящен проверке того, как мои классы обрабатывают ошибки, заполненные executeFetchRequest: error. Я определяю подкласс NSIncrementalStore, который всегда выдает ошибку во время запросов в файле реализации. [NSManagedObjectContext executeFetchRequest:error] обрабатывается [NSPersistentStoreCoordinator executeRequest:withContext:error:], который обрабатывает [NSPersistentStore executeRequest:withContext:error:] во всех магазинах. Вы можете заметить, что слово «выборка» пропадает при переходе к координатору - сохранения и запросы на выборку обрабатываются одним и тем же методом executeRequest:withContext:error:. Таким образом, я получаю покрытие для тестирования на ошибки сохранения и выборки запросов, определяя NSPersistentStore, который всегда будет отвечать на сохранения и выборки с ошибками.

#define kErrorProneStore @"ErrorProneStore"
@interface ErrorProneStore : NSIncrementalStore


@end

@implementation ErrorProneStore

- (BOOL)loadMetadata:(NSError **)error
{
    //Required - Apple's documentation claims you can omit setting this, but I had memory allocation issues without it. 
    NSDictionary * metaData = @{NSStoreTypeKey : kErrorProneStore, NSStoreUUIDKey : @""};
    [self setMetadata:metaData];
    return YES;
}
-(void)populateError:(NSError **)error
{
    if (error != NULL)
    {
        *error = [[NSError alloc] initWithDomain:NSCocoaErrorDomain
                                            code:NSPersistentStoreOperationError
                                        userInfo:nil];
    }
}
- (id)executeRequest:(NSPersistentStoreRequest *)request
         withContext:(NSManagedObjectContext *)context
               error:(NSError **)error
{
    [self populateError:error];
    return nil;
}
- (NSIncrementalStoreNode *)newValuesForObjectWithID:(NSManagedObjectID *)objectID
                                         withContext:(NSManagedObjectContext *)context
                                               error:(NSError **)error
{
    [self populateError:error];
    return nil;
}
- (id)newValueForRelationship:(NSRelationshipDescription *)relationship
              forObjectWithID:(NSManagedObjectID *)objectID
                  withContext:(NSManagedObjectContext *)context
                        error:(NSError **)error
{
    [self populateError:error];
    return nil;
}
- (NSArray *)obtainPermanentIDsForObjects:(NSArray *)array
                                    error:(NSError **)error
{
    [self populateError:error];
    return nil;
}
@end

Теперь вы можете создать базовый стек данных с помощью ErrorProneStore и быть уверенным, что ваши запросы на выборку вернут nil и заполнят параметр error.

- (void)testFetchRequestErrorHandling
{
    NSManagedObjectModel * model = [NSManagedObjectModel mergedModelFromBundles:nil];

    [NSPersistentStoreCoordinator registerStoreClass:[ErrorProneStore class]
                                        forStoreType:kErrorProneStore];

    NSPersistentStoreCoordinator * coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];


    NSManagedObjectContext * context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
    [context setPersistentStoreCoordinator:coordinator];
    [coordinator addPersistentStoreWithType:kErrorProneStore
                              configuration:nil
                                        URL:nil
                                    options:nil
                                      error:nil];

    NSFetchRequest * request = [NSFetchRequest fetchRequestWithEntityName:@"AValidEntity"];

    NSError * error;
    [context executeFetchRequest:request
                           error:&error];

    STAssertNotNil(error, @"Error should always be nil");
}
0 голосов
/ 15 апреля 2016

На мой взгляд, гораздо проще использовать OCMock .

- (void)testCountForEntityFetchError {
  id mockContext =[OCMockObject partialMockForObject:self.context];

  [[[mockContext stub] andCall:@selector(stubbedExecuteFetchRequest:error:) onObject:self] countForFetchRequest:OCMOCK_ANY error:[OCMArg setTo:nil]];

  // Your code goes here
}

- (NSArray *)stubbedExecuteFetchRequest:(NSFetchRequest *)request error:(NSError **)error {
  *error = [NSError errorWithDomain:@"CRTest" code:99 userInfo:nil];
  return nil;
}
...