核心数据单元测试 - 不确定如何在executeFetchRequest中触发错误情况:错误:

ede*_*y05 5 unit-testing core-data ios

根据NSManagedObjectContext类文档 ...

- (NSArray *)executeFetchRequest:(NSFetchRequest *)request error:(NSError **)error
Run Code Online (Sandbox Code Playgroud)

回报价值

符合请求所指定条件的对象数组,该请求是从接收方和与接收方持久存储协调器关联的持久存储中获取的.如果发生错误,则返回nil.如果没有对象符合request指定的条件,则返回一个空数组.

我正在尝试为情况创建单元测试"如果发生错误,则返回nil."

我想远离使用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");
}
Run Code Online (Sandbox Code Playgroud)

有没有一种简单的方法来触发返回nil的获取请求?

Fru*_*eek 4

我有同样的难题。我喜欢尽可能将单元测试覆盖率保持在 100%。没有简单的方法来生成有机错误条件。事实上,我不确定 Core Data 附带的 4 种存储类型的当前实现是否会触发错误来响应executeFetchRequest:error。但由于它可能在未来发生,这就是我所做的:

我有一个单元测试用例文件,专门用于验证我的类如何处理由executeFetchRequest:error 填充的错误。我定义了一个 NSIncrementalStore 的子类,它在实现文件中的请求期间总是产生错误。由所有商店上的哪个进程[NSManagedObjectContext executeFetchRequest:error]进行处理。您可能会注意到,当您移动到协调器时,“获取”一词会消失 -保存和获取请求由相同的方法处理。因此,我通过定义一个始终响应有错误的保存和获取请求的 NSPercientStore 来测试保存错误和获取请求。[NSPersistentStoreCoordinator executeRequest:withContext:error:][NSPersistentStore executeRequest:withContext:error:] executeRequest:withContext:error:

#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
Run Code Online (Sandbox Code Playgroud)

现在,您可以使用 ErrorProneStore 构建核心数据堆栈,并保证您的提取请求将返回 nil 并填充错误参数。

- (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");
}
Run Code Online (Sandbox Code Playgroud)

  • 我没有直接对上下文进行子类化,因为核心数据中的任何事情都不是那么容易的。[NSManagedObjectContextexecuteFetchRequest:error] 由 [NSPersistentStoreCoordinatorexecuteRequest:withContext:error:] 处理,它在所有当前存储上处理 [NSPersistentStoreexecuteRequest:withContext:error:]。您可能会注意到,当您移动到协调器时,“fetch”一词就会消失 - 保存和获取请求由相同的方法executeRequest:withContext:error:处理。因此,我通过定义 ErrorProneStore 来测试保存错误和获取请求。 (2认同)